แชร์ผ่าน


TripPin ส่วนที่ 5 - การแบ่งหน้า

บทช่วยสอนแบบหลายส่วนนี้ครอบคลุมการสร้างส่วนขยายแหล่งข้อมูลใหม่สําหรับ Power Query บทช่วยสอนมีไว้ให้ทําตามลําดับ —บทเรียนแต่ละบทจะสร้างขึ้นบนตัวเชื่อมต่อที่สร้างขึ้นในบทเรียนที่แล้ว โดยการเพิ่มความสามารถใหม่ให้กับตัวเชื่อมต่อของคุณแบบเพิ่มหน่วย

ในบทเรียนนี้ คุณจะ:

  • เพิ่มการสนับสนุนการแบ่งหน้าไปยังตัวเชื่อมต่อ

Rest API จํานวนมากส่งกลับข้อมูลใน "หน้า" ที่จําเป็นต้องมีไคลเอ็นต์เพื่อทําการร้องขอหลายรายการเพื่อใส่ผลลัพธ์เข้าด้วยกัน แม้ว่าจะมีหลักทั่วไปบางอย่างสําหรับการแบ่งหน้า (เช่น RFC 5988) โดยทั่วไปแล้วจะแตกต่างกันจาก API เป็น API โชคดีที่ TripPin เป็นบริการ OData และ มาตรฐาน OData กําหนดวิธีการแบ่งหน้าโดยใช้ ค่า odata.nextLink ที่ส่งกลับในเนื้อความของการตอบสนอง

เพื่อทําให้การเกิดซ้ําก่อนหน้านี้ของตัวเชื่อมต่อTripPin.Feedง่ายขึ้น ฟังก์ชันนี้ไม่ทราบหน้า เพียงแค่แยกวิเคราะห์สิ่งที่ JSON ถูกส่งกลับจากคําขอและจัดรูปแบบเป็นตาราง ผู้ที่คุ้นเคยกับโปรโตคอล OData อาจสังเกตเห็นว่าสมมติฐานที่ไม่ถูกต้องจํานวนมากเกิดขึ้นในรูปแบบ การตอบสนอง (เช่นสมมติว่ามีเขตข้อมูลที่มี value อาร์เรย์ของระเบียน)

ในบทเรียนนี้ คุณปรับปรุงตรรกะการจัดการการตอบกลับของคุณ โดยการทําให้ทราบหน้า บทช่วยสอนในอนาคตทําให้หน้าการจัดการตรรกะมีประสิทธิภาพมากขึ้นและสามารถจัดการรูปแบบการตอบสนองหลายรายการ (รวมถึงข้อผิดพลาดจากบริการ)

หมายเหตุ

คุณไม่จําเป็นต้องใช้ตรรกะการแบ่งหน้าของคุณเองด้วยตัวเชื่อมต่อที่ ยึดตาม OData.Feed เนื่องจากจะจัดการกับทั้งหมดให้คุณโดยอัตโนมัติ

รายการตรวจสอบการแบ่งหน้า

เมื่อมีการใช้การสนับสนุนการแบ่งหน้า คุณจะต้องทราบสิ่งต่อไปนี้เกี่ยวกับ API ของคุณ:

  • คุณจะร้องขอหน้าถัดไปของข้อมูลได้อย่างไร
  • กลไกการแบ่งหน้าเกี่ยวข้องกับการคํานวณค่าหรือคุณแยก URL สําหรับหน้าถัดไปออกจากการตอบสนองหรือไม่
  • คุณจะรู้ได้ไงว่าจะหยุดการแบ่งหน้าเมื่อใด
  • มีพารามิเตอร์ที่เกี่ยวข้องกับการแบ่งหน้าที่คุณควรระวังหรือไม่ (เช่น "ขนาดหน้า")

คําตอบสําหรับคําถามเหล่านี้ส่งผลกระทบต่อวิธีที่คุณใช้ตรรกะการแบ่งหน้าของคุณ ในขณะที่มีการใช้โค้ดซ้ําในการใช้งานการแบ่งหน้า (เช่น การใช้ Table.GenerateByPage แต่ตัวเชื่อมต่อส่วนใหญ่จะต้องใช้ตรรกะแบบกําหนดเอง

หมายเหตุ

บทเรียนนี้ประกอบด้วยตรรกะการแบ่งหน้าสําหรับบริการ OData ซึ่งตามรูปแบบเฉพาะ ตรวจสอบเอกสารประกอบสําหรับ API ของคุณเพื่อกําหนดการเปลี่ยนแปลงที่คุณจะต้องทําในตัวเชื่อมต่อของคุณเพื่อสนับสนุนรูปแบบการแบ่งหน้า

ภาพรวมของการแบ่งหน้า OData

การแบ่งหน้า OData ถูกขับเคลื่อนด้วย คําอธิบายประกอบ nextLink ที่อยู่ภายในส่วนข้อมูลการตอบสนอง ค่า nextLink ประกอบด้วย URL ไปยังหน้าถัดไปของข้อมูล คุณจะทราบว่ามีหน้าอื่นของข้อมูล โดยการค้นหา odata.nextLink เขตข้อมูลในวัตถุด้านนอกสุดในการตอบสนอง ถ้าไม่มี odata.nextLink เขตข้อมูล คุณได้อ่านข้อมูลของคุณทั้งหมดแล้ว

{
  "odata.context": "...",
  "odata.count": 37,
  "value": [
    { },
    { },
    { }
  ],
  "odata.nextLink": "...?$skiptoken=342r89"
}

บริการ OData บางอย่างอนุญาตให้ไคลเอ็นต์ใส่ การกําหนดลักษณะขนาดหน้าสูงสุด แต่ขึ้นอยู่กับบริการว่าจะให้บริการหรือไม่เคารพหรือไม่ Power Query ควรสามารถจัดการการตอบกลับทุกขนาด ดังนั้นคุณไม่ต้องกังวลเกี่ยวกับการระบุการกําหนดลักษณะขนาดหน้า — คุณสามารถสนับสนุนสิ่งใดก็ตามที่บริการนั้นขว้างมาให้คุณ

ข้อมูลเพิ่มเติมเกี่ยวกับ เพจจิ้ง ที่ขับเคลื่อนด้วยเซิร์ฟเวอร์สามารถพบได้ในข้อมูลจําเพาะของ OData

การทดสอบ TripPin

ก่อนที่จะแก้ไขการใช้งานการแบ่งหน้าของคุณ ให้ยืนยันลักษณะการทํางานปัจจุบันของส่วนขยายจาก บทช่วยสอนก่อนหน้า คิวรีทดสอบต่อไปนี้จะเรียกใช้ตาราง บุคคล และเพิ่มคอลัมน์ดัชนีเพื่อแสดงจํานวนแถวปัจจุบันของคุณ

let
    source = TripPin.Contents(),
    data = source{[Name="People"]}[Data],
    withRowCount = Table.AddIndexColumn(data, "Index")
in
    withRowCount

เปิดใช้งาน Fiddler และเรียกใช้คิวรีใน Power Query SDK โปรดทราบว่าคิวรีจะส่งกลับตารางที่มีแปดแถว (ดัชนี 0 ถึง 7)

QueryWithoutPaging

ถ้าคุณดูที่เนื้อความของการตอบกลับจาก fiddler คุณจะเห็นว่า อันที่จริงแล้วมี @odata.nextLink เขตข้อมูล แสดงว่ามีหน้าข้อมูลที่พร้อมใช้งานมากกว่า

{
  "@odata.context": "https://services.odata.org/V4/TripPinService/$metadata#People",
  "@odata.nextLink": "https://services.odata.org/v4/TripPinService/People?%24skiptoken=8",
  "value": [
    { },
    { },
    { }
  ]
}

การใช้การแบ่งหน้าสําหรับ TripPin

ในตอนนี้คุณกําลังทําการเปลี่ยนแปลงต่อไปนี้กับส่วนขยายของคุณ:

  1. นําเข้าฟังก์ชันทั่วไปTable.GenerateByPage
  2. GetAllPagesByNextLinkเพิ่มฟังก์ชันที่ใช้Table.GenerateByPageกาวหน้าทั้งหมดเข้าด้วยกัน
  3. GetPageเพิ่มฟังก์ชันที่สามารถอ่านหน้าข้อมูลเดียวได้
  4. GetNextLinkเพิ่มฟังก์ชันเพื่อแยก URL ถัดไปจากคําตอบ
  5. อัปเดต TripPin.Feed เพื่อใช้ฟังก์ชันตัวอ่านหน้าใหม่

หมายเหตุ

ตามที่ระบุไว้ก่อนหน้านี้ในบทช่วยสอน นี้ ตรรกะการแบ่งหน้าจะแตกต่างกันระหว่างแหล่งข้อมูล การดําเนินการที่นี่พยายามแบ่งตรรกะออกเป็นฟังก์ชันที่ควรนํามาใช้ใหม่สําหรับแหล่งข้อมูลที่ใช้ ลิงก์ ถัดไปที่ส่งกลับในการตอบสนอง

Table.GenerateByPage

เมื่อต้องรวมหลายหน้า (อาจเป็น) หลายหน้าที่ส่งกลับโดยแหล่งข้อมูลลงในตารางเดียว เราจะใช้Table.GenerateByPage ฟังก์ชันนี้ใช้เป็นอาร์กิวเมนต์สําหรับ getNextPage ฟังก์ชันที่ควรทําตามที่ชื่อแนะนํา: ดึงข้อมูลหน้าถัดไป Table.GenerateByPage จะเรียกใช้ getNextPage ฟังก์ชันซ้ํา ๆ แต่ละครั้งที่ส่งผ่านผลลัพธ์ที่สร้างขึ้นในครั้งสุดท้ายที่ถูกเรียกจนกว่าจะกลับไป null ส่งสัญญาณกลับว่าไม่มีหน้าที่พร้อมใช้งานอีก

เนื่องจากฟังก์ชันนี้ไม่ใช่ส่วนหนึ่งของไลบรารีมาตรฐานของ Power Query คุณจะต้องคัดลอกรหัสต้นทางลงในไฟล์ .pq ของคุณ

เนื้อความของฟังก์ชันของคุณGetAllPagesByNextLinkใช้getNextPageอาร์กิวเมนต์ฟังก์ชันสําหรับTable.GenerateByPage ซึ่งจะเรียกใช้ GetPage ฟังก์ชัน และดึงข้อมูล URL สําหรับหน้าถัดไปของข้อมูลจาก NextLink เขตข้อมูลของ meta เรกคอร์ดจากการเรียกก่อนหน้า

// Read all pages of data.
// After every page, we check the "NextLink" record on the metadata of the previous request.
// Table.GenerateByPage will keep asking for more pages until we return null.
GetAllPagesByNextLink = (url as text) as table =>
    Table.GenerateByPage((previous) => 
        let
            // if previous is null, then this is our first page of data
            nextLink = if (previous = null) then url else Value.Metadata(previous)[NextLink]?,
            // if NextLink was set to null by the previous call, we know we have no more data
            page = if (nextLink <> null) then GetPage(nextLink) else null
        in
            page
    );

ใช้ GetPage

ฟังก์ชันของคุณ GetPage จะใช้ Web.Contents เพื่อดึงข้อมูลหน้าเดียวจากบริการ TripPin และแปลงการตอบสนองเป็นตาราง ซึ่งจะส่งการตอบสนองจาก Web.Contents ไปยัง GetNextLink ฟังก์ชันเพื่อแยก URL ของหน้าถัดไป และตั้งค่าบน meta ระเบียนของตารางที่ส่งกลับ (หน้าของข้อมูล)

การใช้งานนี้เป็นการเรียกใช้เวอร์ชัน TripPin.Feed ที่ปรับเปลี่ยนเล็กน้อยจากบทช่วยสอนก่อนหน้า

GetPage = (url as text) as table =>
    let
        response = Web.Contents(url, [ Headers = DefaultRequestHeaders ]),        
        body = Json.Document(response),
        nextLink = GetNextLink(body),
        data = Table.FromRecords(body[value])
    in
        data meta [NextLink = nextLink];

ฟังก์ชันของคุณ GetNextLink เพียงแค่ตรวจสอบเนื้อความของการตอบกลับสําหรับ @odata.nextLink เขตข้อมูล และส่งกลับค่า

// In this implementation, 'response' will be the parsed body of the response after the call to Json.Document.
// Look for the '@odata.nextLink' field and simply return null if it doesn't exist.
GetNextLink = (response) as nullable text => Record.FieldOrDefault(response, "@odata.nextLink");

รวมทุกอย่างเข้าด้วยกัน

ขั้นตอนสุดท้ายในการใช้ตรรกะการแบ่งหน้าของคุณคือการอัปเดต TripPin.Feed เพื่อใช้ฟังก์ชันใหม่ ในตอนนี้ คุณเพียงแค่โทรผ่านไปยัง GetAllPagesByNextLinkแต่ในบทช่วยสอนต่อไป คุณจะเพิ่มความสามารถใหม่ (เช่น การบังคับใช้ Schema และตรรกะของพารามิเตอร์คิวรี)

TripPin.Feed = (url as text) as table => GetAllPagesByNextLink(url);

ถ้าคุณเรียกใช้คิวรีทดสอบเดียวกันจากก่อนหน้านี้ในบทช่วยสอนตอนนี้คุณควรเห็นการทํางานของตัวอ่านหน้า นอกจากนี้คุณควรเห็นว่าคุณมี 24 แถวในการตอบกลับแทนที่จะเป็นแปดแถว

QueryWithPaging

ถ้าคุณดูคําขอใน fiddler ตอนนี้คุณควรเห็นคําขอแยกต่างหากสําหรับแต่ละหน้าของข้อมูล

ฟิดดเลอร์

หมายเหตุ

คุณจะสังเกตเห็นคําขอซ้ําสําหรับหน้าแรกของข้อมูลจากบริการ ซึ่งไม่เหมาะสม คําขอเพิ่มเติมคือผลลัพธ์ของลักษณะการทํางานของการตรวจสอบ Schema ของกลไกจัดการ M ละเว้นปัญหานี้ในตอนนี้และแก้ไขปัญหาใน บทช่วยสอนถัดไป ซึ่งคุณจะใช้ Schema ที่ชัดเจน

บทสรุป

บทเรียนนี้แสดงวิธีใช้การสนับสนุนการแบ่งหน้าสําหรับ Rest API ในขณะที่ตรรกะอาจแตกต่างกันระหว่าง API แต่รูปแบบที่กําหนดไว้ที่นี่ควรนํามาใช้ใหม่ด้วยการปรับเปลี่ยนเล็กน้อย

ในบทเรียนถัดไป คุณจะได้ดูวิธีการใช้ Schema ที่ชัดเจนกับข้อมูลของคุณ ซึ่งนอกเหนือจากชนิดข้อมูลและnumberรูปแบบธรรมดาtextที่คุณได้รับจากJson.Document

ขั้นตอนถัดไป

TripPin ส่วนที่ 6 - Schema