บทช่วยสอน: สร้างแผนที่แบบคงที่โดยใช้ REST API และ Python

Fabric Maps ถูกกําหนดโดย คําจํากัดความสาธารณะ (map.json) ที่อธิบายแผนที่ฐาน แหล่งข้อมูล แหล่งที่มาของเลเยอร์ และลักษณะการแสดงผล

บทช่วยสอนนี้สาธิต สถานการณ์ข้อมูลแบบคงที่ โดยใช้ไฟล์ที่จัดเก็บไว้ในเลคเฮาส์ สําหรับสถานการณ์การสตรีมแบบเรียลไทม์โดยใช้ Eventstream และ Eventhouse โปรดดู สร้างแผนที่แบบเรียลไทม์โดยใช้ REST API และ Python

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

หากต้องการข้อมูลเพิ่มเติมเกี่ยวกับโครงสร้างข้อกําหนดแผนที่ โปรดดู ข้อกําหนดรายการแผนที่

เมื่อใช้ Fabric REST API คุณจะทําสิ่งต่อไปนี้

  • สร้างเลคเฮาส์โดยใช้ Fabric REST API
  • อัปโหลดไฟล์ GeoJSON ไปยัง OneLake
  • อัปโหลดไอคอนเครื่องหมาย SVG ที่กําหนดเองไปยัง OneLake
  • สร้างคําจํากัดความ map.json ที่อ้างอิงข้อมูล Lakehouse
  • สร้างแผนที่ด้วยคําจํากัดความที่ให้ไว้ในบรรทัด

บทช่วยสอนนี้เป็นไปตามรูปแบบระบบอัตโนมัติทั่วไปใน Fabric: สร้างโครงสร้างพื้นฐาน→อัปโหลดข้อมูล→กําหนดการแสดงภาพ→แสดงแผนที่

เมื่อใดที่ควรใช้วิธีนี้

รูปแบบนี้เหมาะที่สุดสําหรับ:

  • ชุดข้อมูลเชิงพื้นที่แบบคงที่
  • เลเยอร์อ้างอิง (เช่น จุดสนใจ ขอบเขต)
  • ข้อมูลในอดีตหรือข้อมูลที่ประมวลผลเป็นชุด

สําหรับสถานการณ์ที่ต้องอัปเดตข้อมูลอย่างต่อเนื่อง (เช่น การติดตามแบบสดหรือการวัดและส่งข้อมูลทางไกล) โปรดดู สร้างแผนที่แบบเรียลไทม์โดยใช้ REST API และ Python

ข้อกำหนดเบื้องต้น

  • Python 3.10 หรือใหม่กว่า
  • Azure CLI
  • รหัสพื้นที่ทํางาน Fabric
  • สิทธิ์ในการเรียก Fabric REST API เช่น:
    • Item.ReadWrite.All

Note

ขอบเขตที่ได้รับมอบหมาย เช่น Item.ReadWrite.All มอบให้กับข้อมูลประจําตัวที่ลงชื่อเข้าใช้ผ่านบทบาทพื้นที่ทํางาน ตรวจสอบให้แน่ใจว่าข้อมูลประจําตัวที่คุณใช้กับ az login ถูกกําหนดบทบาท Contributor, Member หรือ Admin บนพื้นที่ทํางาน Fabric เป้าหมายก่อนที่จะเรียกใช้สคริปต์

การรับรองความถูกต้อง

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

  1. เปิดเทอร์มินัล
  2. วิ่ง:
az login

DefaultAzureCredential สามารถใช้ข้อมูลประจําตัวที่ลงชื่อเข้าใช้เพื่อรับโทเค็นเพื่อการเข้าถึงสําหรับสิ่งต่อไปนี้

  • Fabric REST API (ทรัพยากร: https://api.fabric.microsoft.com/.default)
  • การเข้าถึง OneLake ผ่าน ADLS Gen2 API และ SDK รวมถึงการกําหนดที่อยู่ตาม GUID สําหรับพื้นที่ทํางานและรายการ

Tip

เกี่ยวกับ https://api.fabric.microsoft.com/.default ค่านี้เป็น ขอบเขตคําขอโทเค็น ไม่ใช่ URL ที่คุณเรียกใช้โดยตรง จะบอก Microsoft Entra ว่าควรออกโทเค็นการเข้าถึงสําหรับ Microsoft Fabric REST API และควรรวม สิทธิ์ Fabric ทั้งหมดที่มอบให้กับ ข้อมูลประจําตัวที่รับรองความถูกต้องแล้ว (เช่น Item.ReadWrite.All หรือ Workspace.ReadWrite.All)

ขอบเขตจะใช้ .default เฉพาะระหว่างการรับโทเค็น และจะไม่ถูกส่งไปยังตําแหน่งข้อมูล Fabric REST API

สําหรับข้อมูลเพิ่มเติมเกี่ยวกับวิธี.defaultการทํางานของขอบเขตในแพลตฟอร์มข้อมูลประจําตัวของ Microsoft ให้ดูที่ ขอบเขตและสิทธิ์ในแพลตฟอร์มข้อมูลประจําตัวของ Microsoft

ก่อนที่คุณจะเรียกใช้บทช่วยสอนนี้ เราขอแนะนําให้ลงชื่อเข้าใช้ Microsoft Fabric อย่างน้อยหนึ่งครั้ง:

https://app.fabric.microsoft.com

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

ขั้นตอนนี้มีประโยชน์อย่างยิ่งในกรณีต่อไปนี้

  • คุณเพิ่งเริ่มใช้ Microsoft Fabric
  • พื้นที่ทํางานเพิ่งสร้างขึ้น
  • เพิ่มการมอบหมายบทบาทของคุณเมื่อเร็วๆ นี้

Note

บทช่วยสอนนี้รับรองความถูกต้องโดยใช้ Microsoft Entra ID ผ่านDefaultAzureCredential Fabric REST API ไม่จําเป็นต้องมีเซสชันเบราว์เซอร์ แต่การลงชื่อเข้าใช้ประสบการณ์เว็บ Fabric สามารถป้องกันปัญหาการอนุญาตการเรียกใช้ครั้งแรกที่เกิดจากการเตรียมใช้งานบทบาทที่ล่าช้า

สร้างไฟล์ GeoJSON

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

คัดลอก GeoJSON ต่อไปนี้ลงในไฟล์ข้อความเปล่า และบันทึกไฟล์เป็น starbucks-seattle.geojson:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": { "name": "Starbucks - 999 3rd Ave" },
      "geometry": { "type": "Point", "coordinates": [-122.334389, 47.605278] }
    },
    {
      "type": "Feature",
      "properties": { "name": "Starbucks - 1201 3rd Ave" },
      "geometry": { "type": "Point", "coordinates": [-122.335167, 47.608040] }
    },
    {
      "type": "Feature",
      "properties": { "name": "Starbucks - 221 Pike St" },
      "geometry": { "type": "Point", "coordinates": [-122.340057, 47.609450] }
    },
    {
      "type": "Feature",
      "properties": { "name": "Starbucks - 800 5th Ave" },
      "geometry": { "type": "Point", "coordinates": [-122.330048, 47.604550] }
    },
    {
      "type": "Feature",
      "properties": { "name": "Starbucks - 1420 5th Ave" },
      "geometry": { "type": "Point", "coordinates": [-122.334091, 47.610041] }
    },
    {
      "type": "Feature",
      "properties": { "name": "Starbucks - 1524 7th Ave" },
      "geometry": { "type": "Point", "coordinates": [-122.334915, 47.614498] }
    },
    {
      "type": "Feature",
      "properties": { "name": "Starbucks - 2011 7th Ave" },
      "geometry": { "type": "Point", "coordinates": [-122.338165, 47.616341] }
    },
    {
      "type": "Feature",
      "properties": { "name": "Starbucks - 2001 8th Ave" },
      "geometry": { "type": "Point", "coordinates": [-122.338806, 47.616848] }
    },
    {
      "type": "Feature",
      "properties": { "name": "Starbucks - 4147 University Way NE" },
      "geometry": { "type": "Point", "coordinates": [-122.313873, 47.658298] }
    },
    {
      "type": "Feature",
      "properties": { "name": "Starbucks - 2200 NW Market St" },
      "geometry": { "type": "Point", "coordinates": [-122.384056, 47.668581] }
    },
    {
      "type": "Feature",
      "properties": { "name": "Starbucks - 101 Broadway E" },
      "geometry": { "type": "Point", "coordinates": [-122.320457, 47.620480] }
    },
    {
      "type": "Feature",
      "properties": { "name": "Starbucks - 824 E Pike St" },
      "geometry": { "type": "Point", "coordinates": [-122.320282, 47.614212] }
    },
    {
      "type": "Feature",
      "properties": { "name": "Starbucks - 6501 California Ave SW" },
      "geometry": { "type": "Point", "coordinates": [-122.387016, 47.545376] }
    },
    {
      "type": "Feature",
      "properties": { "name": "Starbucks - 1501 4th Ave" },
      "geometry": { "type": "Point", "coordinates": [-122.336212, 47.610325] }
    },
    {
      "type": "Feature",
      "properties": { "name": "Starbucks - 701 5th Ave" },
      "geometry": { "type": "Point", "coordinates": [-122.330704, 47.604298] }
    },
    {
      "type": "Feature",
      "properties": { "name": "Starbucks - 2344 Eastlake Ave E" },
      "geometry": { "type": "Point", "coordinates": [-122.325874, 47.640884] }
    },
    {
      "type": "Feature",
      "properties": { "name": "Starbucks - 5221 15th Ave NW" },
      "geometry": { "type": "Point", "coordinates": [-122.376595, 47.668210] }
    },
    {
      "type": "Feature",
      "properties": { "name": "Starbucks - 4408 Fauntleroy Way SW" },
      "geometry": { "type": "Point", "coordinates": [-122.377693, 47.564991] }
    },
    {
      "type": "Feature",
      "properties": { "name": "Starbucks - 7303 35th Ave NE" },
      "geometry": { "type": "Point", "coordinates": [-122.290611, 47.682518] }
    },
    {
      "type": "Feature",
      "properties": { "name": "Starbucks - 2742 Alki Ave SW" },
      "geometry": { "type": "Point", "coordinates": [-122.408028, 47.579311] }
    }
  ]
}

สำคัญ

ตรวจสอบให้แน่ใจว่าเส้นทางไฟล์ที่ใช้ใน local_geojson_path ตรงกับตําแหน่งที่คุณบันทึกไฟล์บนเครื่องของคุณ

ขั้นตอนที่ 1 - สร้างไฟล์โปรเจ็กต์ Python ใหม่

ในขั้นตอนนี้ คุณจะสร้างไฟล์ Python เปล่าที่คุณจะสร้างทีละส่วน

สร้างไฟล์ใหม่ที่มีชื่อว่า

create_map_from_geojson.py

เปิดไฟล์ในเครื่องมือแก้ไข

ขั้นตอนที่ 2 - ติดตั้งไลบรารีที่จําเป็นและเพิ่มคําสั่งนําเข้าที่จําเป็น

ในขั้นตอนนี้ คุณติดตั้งการขึ้นต่อกัน และเพิ่มการนําเข้าที่สคริปต์ของคุณใช้

ติดตั้งไลบรารีที่จําเป็น

วิ่ง:

pip install httpx azure-identity azure-storage-file-datalake

แต่ละห้องสมุดมีไว้เพื่ออะไร

  • httpx: ส่งคําขอ HTTP ไปยัง Fabric REST API
  • azure-identity: ให้ DefaultAzureCredential สําหรับการรับรองความถูกต้อง Microsoft Entra
  • azure-storage-file-datalake: อัปโหลดไฟล์ไปยัง OneLake โดยใช้ API ที่เข้ากันได้กับ ADLS Gen2

เพิ่มคําสั่งนําเข้าลงในไฟล์ .py ของคุณ

ที่ด้านบนของ create_map_from_geojson.py ให้เพิ่มสิ่งต่อไปนี้

import base64
import json
import os
import time
import uuid
from pathlib import Path

import httpx
from azure.identity import DefaultAzureCredential
from azure.storage.filedatalake import DataLakeServiceClient

ขั้นตอนที่ 3 - เพิ่มส่วนการกําหนดค่า

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

การรวมศูนย์การกําหนดค่าในคลาสเดียว Config — แทนที่จะกระจายค่าฮาร์ดโค้ดข้ามฟังก์ชัน — ให้ข้อได้เปรียบที่เป็นรูปธรรมสามประการแก่คุณ:

  • การเคลื่อนย้ายสภาพแวดล้อม: รหัสพื้นที่ทํางาน เส้นทางไฟล์ และชื่อทรัพยากรอยู่ในที่เดียว คุณจึงสามารถเรียกใช้สคริปต์ซ้ํากับพื้นที่ทํางานหรือเครื่องอื่นได้โดยการเปลี่ยนสองสามบรรทัด (หรือตัวแปรสภาพแวดล้อม) แทนการค้นหาโค้ด
  • ลายเซ็นฟังก์ชันที่สะอาดขึ้น: ฟังก์ชันขั้นตอนยอมรับวัตถุเดียว cfg แทนรายการพารามิเตอร์ที่ยาว ซึ่งช่วยให้การประสานงานอ่าน main() ง่าย
  • การจัดการข้อมูลลับที่ปลอดภัยยิ่งขึ้น: ค่าที่ละเอียดอ่อน เช่น รหัสพื้นที่ทํางาน ถูกโหลดจากตัวแปรสภาพแวดล้อม ดังนั้นจึงไม่เคยถูกส่งไปพร้อมกับสคริปต์

เพิ่มข้อความต่อไปนี้ด้านล่างคําสั่ง นําเข้า :

# =========================================================
# Configuration (centralized)
# =========================================================

class Config:
    """
    Central configuration: workspace ID, file paths, resource names, and
    toggles for the optional custom SVG marker. A single instance is built
    in main() and passed to each step function.
    """
    def __init__(self):
        # Workspace
        self.workspace_id = os.environ.get("FABRIC_WORKSPACE_ID", "")
        if not self.workspace_id:
            raise RuntimeError("Set FABRIC_WORKSPACE_ID environment variable before running the script.")

        # Local file (source) and OneLake destination paths (inside Lakehouse Files/)
        self.local_geojson_path = Path(r"C:\tutorial\starbucks-seattle.geojson")
        self.geojson_relative_path = "Files/vector/starbucks-seattle.geojson"

        # Optional SVG marker settings
        self.svg_relative_path = "Files/icons/starbucks-marker.svg"
        self.use_custom_svg_marker = True
        self.builtin_icon_name_fallback = "BuildingShop"

        # SVG content (kept < 1 MB, scales cleanly)
        self.starbucks_marker_svg = """\
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64">
  <path d="M32 2C20.4 2 11 11.4 11 23c0 15.6 18.7 36.6 19.5 37.5a2 2 0 0 0 3 0C34.3 59.6 53 38.6 53 23 53 11.4 43.6 2 32 2z"
        fill="#006241" stroke="#ffffff" stroke-width="2"/>
  <circle cx="32" cy="23" r="13" fill="#ffffff" opacity="0.95"/>
  <path d="M26 20h12v10c0 3-2.5 5-6 5s-6-2-6-5V20z" fill="#006241"/>
</svg>
"""

        # Resource display names / descriptions
        self.lakehouse_display_name = "lh_starbucks_seattle"
        self.lakehouse_description = "Stores Starbucks Seattle GeoJSON + marker icon for a Fabric Maps tutorial"

        self.map_display_name = "My Fabric Map"
        self.map_description = "Created using Fabric Maps REST API"


ตั้งค่ารหัสพื้นที่ทํางานโดยใช้ตัวแปรสภาพแวดล้อม

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

ก่อนเรียกใช้สคริปต์ ให้สร้างตัวแปรสภาพแวดล้อมชื่อ FABRIC_WORKSPACE_ID.

สำคัญ

ตัวแปรสภาพแวดล้อมที่ตั้งค่าจากเทอร์มินัลมีอยู่ภายในเซสชันเทอร์มินัลเดียวเท่านั้น ไม่ได้แชร์กับหน้าต่างเทอร์มินัลอื่น ๆ ด้วยประเภทเชลล์อื่น หรือกับกระบวนการที่เปิดตัวนอกเทอร์มินัลนั้น รวมถึงสคริปต์ที่เริ่มต้นจากปุ่มเรียกใช้ของ VS Code ซึ่งมักจะสร้างเทอร์มินัลของตัวเอง หากสคริปต์ไม่พบตัวแปร แสดงว่าสคริปต์ล้มเหลวด้วยSet FABRIC_WORKSPACE_ID environment variable before running the script

เพื่อหลีกเลี่ยงปัญหานี้ ให้เรียกใช้สคริปต์จาก เซสชันเทอร์มินัลเดียวกัน ที่คุณตั้งค่าตัวแปร หรือตั้งค่าอย่างต่อเนื่อง (ดูส่วน Windows และ macOS/Linux ที่ตามมา) เพื่อให้ทุกเซสชันเทอร์มินัลใหม่รับโดยอัตโนมัติ

ตั้งค่าตัวแปรสภาพแวดล้อมบน Windows

บน Windows คุณสามารถตั้งค่าตัวแปรจากเทอร์มินัลใดก็ได้ที่รองรับตัวแปรสภาพแวดล้อม เช่น PowerShell, Windows PowerShell, PowerShell หรือ Command Prompt windows ที่สร้างขึ้นใน Visual Studio และ Visual Studio Code, เทอร์มินัล Windows และส่วนใหญ่ เปลือกหอยอื่น ๆ

เรียกใช้สิ่งต่อไปนี้ใน PowerShell หรือเทอร์มินัลแบบรวม VS Code:

$env:FABRIC_WORKSPACE_ID="<WORKSPACE_ID>"

เพื่อยืนยันว่าตัวแปรถูกตั้งค่า:

echo $env:FABRIC_WORKSPACE_ID

สิ่งนี้จะตั้งค่าตัวแปรสําหรับเซสชันเทอร์มินัลปัจจุบันเท่านั้น

ตั้งค่าตัวแปรสภาพแวดล้อมถาวร (Windows)

หากต้องการให้ตัวแปรพร้อมใช้งานในเซสชันในอนาคต ให้ใช้วิธีใดวิธีหนึ่งต่อไปนี้

  • PowerShell (บรรทัดเดียว): เรียกใช้setx FABRIC_WORKSPACE_ID "<WORKSPACE_ID>" setxคําสั่งจะเขียนไปยังสภาพแวดล้อมของผู้ใช้ แต่จะไม่อัปเดตเทอร์มินัลปัจจุบัน ให้ปิดและเปิดเทอร์มินัลอีกครั้ง (หรือเปิดเทอร์มินัลใหม่) ก่อนเรียกใช้สคริปต์
  • จีโอ:
    1. เปิด คุณสมบัติของระบบ
    2. เลือก การตั้งค่าระบบขั้นสูง
    3. เลือกตัวแปรสภาพแวดล้อม
    4. ภายใต้ ตัวแปรผู้ใช้ ให้เลือก สร้าง
    5. ป้อน:
      • ชื่อ: FABRIC_WORKSPACE_ID
      • ค่า: รหัสพื้นที่ทํางานของคุณ
    6. เลือก ตกลง เพื่อบันทึก
    7. ปิดและเปิดเทอร์มินัลของคุณอีกครั้งก่อนที่จะเรียกใช้สคริปต์อีกครั้ง

ตั้งค่าตัวแปรสภาพแวดล้อมบน macOS หรือ Linux

บน macOS และ Linux คุณสามารถตั้งค่าตัวแปรจากเชลล์ใดก็ได้ที่รองรับ export—Bash, Zsh (ค่าเริ่มต้นใน macOS สมัยใหม่), Fish (ด้วยไวยากรณ์ที่แตกต่างกันเล็กน้อย) และเทอร์มินัลในตัวใน Visual Studio Code และตัวแก้ไขอื่นๆ

วิ่ง:

export FABRIC_WORKSPACE_ID="<WORKSPACE_ID>"

เพื่อยืนยันว่าตัวแปรถูกตั้งค่า:

echo $FABRIC_WORKSPACE_ID

สิ่งนี้ตั้งค่าตัวแปรสําหรับเซสชันเชลล์ปัจจุบันเท่านั้น

ตั้งค่าตัวแปรสภาพแวดล้อมถาวร (macOS หรือ Linux)

หากต้องการให้ตัวแปรพร้อมใช้งานในเซสชันในอนาคต ให้เพิ่มบรรทัดลงใน export โปรไฟล์เชลล์ของคุณ:

  • Zsh (ค่าเริ่มต้นบน macOS): ~/.zshrc
  • ทุบตี: ~/.bashrc (Linux) หรือ ~/.bash_profile (macOS)
  • ปลา: เรียกใช้ set -Ux FABRIC_WORKSPACE_ID "<WORKSPACE_ID>" แทนการแก้ไขไฟล์

หลังจากอัปเดตโปรไฟล์แล้ว ให้เปิดเทอร์มินัลใหม่หรือเรียกใช้ source ~/.zshrc (หรือไฟล์ที่เหมาะสม) เพื่อให้การเปลี่ยนแปลงมีผล

Note

ค่า geojson_relative_path และ svg_relative_path กําหนดตําแหน่งภายในพื้นที่ ไฟล์เลคเฮาส์ เส้นทางเหล่านี้สัมพันธ์กับรากของ Lakehouse และใช้ทั้งสําหรับการอัปโหลดไฟล์และการอ้างอิงในคําจํากัดความของแผนที่

ขั้นตอนที่ 4 - เพิ่มฟังก์ชันตัวช่วย

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

การรวมศูนย์ข้อกังวลเหล่านี้ไว้ในผู้ช่วย แทนที่จะรวมไว้ในทุกไซต์การโทร ให้ข้อดีที่เป็นรูปธรรมสามประการแก่คุณ:

  • แหล่งข้อมูลเดียวสําหรับข้อกังวลข้ามด้าน: การรับรองความถูกต้อง ส่วนหัว และการสํารวจ LRO เป็นสิ่งจําเป็นสําหรับการเรียก API เกือบทุกครั้ง การรวมศูนย์ทําให้ฟังก์ชันแต่ละขั้นตอนมุ่งเน้นไปที่ทรัพยากรของตัวเองแทนที่จะใช้ตรรกะการรับโทเค็นและลองใหม่อีกครั้ง
  • ความยืดหยุ่นโดยไม่ยุ่งเหยิง: ตัวช่วยดูดซับเงื่อนไขชั่วคราว เช่น การจัดเตรียมแบบอะซิงโครนัส ความล่าช้าในการเผยแพร่แบ็กเอนด์ ความล้มเหลวในการอัปโหลดที่ลองใหม่ได้ ดังนั้นฟังก์ชันขั้นตอนจึงสั้นและอ่านเหมือนรายการตรวจสอบ
  • สอนและแก้ไขได้ง่ายขึ้น: ตัวช่วยแต่ละคนจะถูกนํามาใช้เพียงครั้งเดียวและนํากลับมาใช้ใหม่ หาก Fabric เปลี่ยนรูปแบบ LRO หรือขอบเขตการรับรองความถูกต้อง คุณจะแก้ไขได้ในที่เดียว

ตัวช่วยที่คุณเพิ่มในขั้นตอนนี้คือ:

  • ตัวช่วยการรับรองความถูกต้อง: สร้างส่วนหัวสําหรับ REST API Fabric (และปลายทาง LRO ของคลัสเตอร์ Power BI)
  • FabricClient: ตัวห่อหุ้มน้ําหนักเบาสําหรับการเรียก API ที่สอดคล้องกัน
  • ตัวจัดการ LRO: สํารวจการดําเนินการที่ทํางานเป็นเวลานานโดยใช้ Location / x-ms-operation-id / Retry-After รวมถึงการตอบสนอง 200-with-Running จุดสิ้นสุดคลัสเตอร์ Power BI และเพย์โหลดการเสร็จสมบูรณ์ตามสถานะเท่านั้น (แก้ไขโดย displayName)
  • ตัวช่วยเพย์โหลดคําจํากัดความ: base64-encode map.json สําหรับคําจํากัดความแบบอินไลน์
  • ตัวช่วยอัปโหลด OneLake: อัปโหลดไฟล์ GeoJSON และ SVG ไปยังไฟล์ Lakehouse ด้วยการลองอีกครั้ง

Note

บทช่วยสอนนี้ครอบคลุมสองระนาบ:

  • Control plane (Fabric REST API): สร้างไอเท็มเลคเฮาส์และแผนที่
  • ระนาบข้อมูล (OneLake DFS): อัปโหลดไฟล์ไปยังเลคเฮาส์

ทั้งสองจะต้องตั้งค่าแผนที่อย่างสมบูรณ์

สร้างฟังก์ชันตัวช่วยการรับรองความถูกต้อง

ทุก Fabric REST ที่บทช่วยสอนนี้ทําจะมีโทเค็นการเข้าถึง Microsoft Entra (โทเค็นผู้ถือ) ในส่วนหัว Authorization แทนที่จะได้มาซึ่งโทเค็นเฉพาะกิจขั้นตอนนี้จะห่อหุ้ม DefaultAzureCredential ด้วยขนาดเล็ก TokenProvider และเปิดเผยตัวสร้างส่วนหัวเฉพาะกลุ่มเป้าหมายสําหรับแต่ละตระกูลปลายทางที่สคริปต์เรียกใช้

การรวมศูนย์การได้มาซึ่งโทเค็นและการสร้างส่วนหัวในตัวช่วย — แทนที่จะรับโทเค็นในทุกไซต์การโทร — ให้ข้อได้เปรียบที่เป็นรูปธรรมสามประการแก่คุณ:

  • ข้อมูลประจําตัวแบบรวมศูนย์: DefaultAzureCredential เดียวถูกห่อไว้ใน TokenProvider และนํามาใช้ซ้ําสําหรับการเรียก API ทุกครั้ง ดังนั้นการค้นพบข้อมูลประจําตัว (Azure CLI, VS Code, ข้อมูลประจําตัวที่มีการจัดการ ฯลฯ) จะเกิดขึ้นเพียงครั้งเดียว
  • โทเค็นที่รับรู้กลุ่มเป้าหมาย: Fabric REST API และตําแหน่งข้อมูล LRO ของคลัสเตอร์ Power BI ต้องการโทเค็นที่ออกสําหรับกลุ่มเป้าหมายที่แตกต่างกัน เครื่องมือสร้างส่วนหัวแยกต่างหากต่อกลุ่มเป้าหมายจะเก็บขอบเขตที่ถูกต้องไว้ถัดจากไซต์การโทร ดังนั้นจึงเห็นได้ชัดว่าแต่ละฟังก์ชันกําหนดเป้าหมายปลายทางใด
  • สดใหม่ในทุกคําขอ: ผู้ Authorization สร้างส่วนหัวสร้างส่วนหัวตามความต้องการแทนที่จะแคชโทเค็นเอง ข้อมูลประจําตัวพื้นฐานจะรีเฟรชอย่างโปร่งใส ดังนั้นไซต์การโทรจึงไม่ต้องคิดถึงวันหมดอายุ

บทช่วยสอนนี้เรียกใช้ REST API Fabric โดยใช้ขอบเขตที่ได้รับมอบหมาย เช่น Item.ReadWrite.All (หรือ Lakehouse.ReadWrite.All สําหรับการดําเนินการเฉพาะของ Lakehouse)

เพิ่มสิ่งต่อไปนี้หลัง Config ชั้นเรียน

# =========================================================
# Auth helpers
#
# Authentication utilities built on `DefaultAzureCredential` that acquire and
# construct Authorization headers for calling Fabric REST APIs.
# =========================================================

class TokenProvider:
    """
    Thin wrapper around `DefaultAzureCredential` that acquires Entra access
    tokens. `_fabric_headers()` and `_pbi_headers()` call `get()` per
    request so the Authorization header is always fresh; the underlying
    credential refreshes transparently.
    """
    def __init__(self):
        self._cred = DefaultAzureCredential()

    def get(self, scope: str) -> str:
        return self._cred.get_token(scope).token


_tokens = TokenProvider()


def _fabric_headers() -> dict[str, str]:
    """
    Build headers for Fabric REST API calls.

    This function is called each time we make a Fabric REST call so the token is fresh.
    """
    return {
        "Authorization": f"Bearer {_tokens.get('https://api.fabric.microsoft.com/.default')}",
        "Content-Type": "application/json"
    }


def _pbi_headers() -> dict[str, str]:
    """
    Build headers for polling Power BI cluster LRO endpoints
    (e.g., df-*.analysis.windows.net) that require a Power BI audience token.
    """
    return {
        "Authorization": f"Bearer {_tokens.get('https://analysis.windows.net/powerbi/api/.default')}",
        "Content-Type": "application/json"
    }

Note

การดําเนินการที่ทํางานเป็นเวลานาน (LRO) Fabric บางรายการโฮสต์บนจุดสิ้นสุดคลัสเตอร์ Power BI (*.analysis.windows.net) แทนที่จะเป็นบน api.fabric.microsoft.com ปลายทางเหล่านั้นต้องใช้โทเค็นผู้ชม Power BI ดังนั้นตัวช่วย LRO จะเปลี่ยนเป็น _pbi_headers() โดยอัตโนมัติเมื่อตรวจพบ URL การสํารวจนั้น

สร้าง Fabric Client Wrapper

การเรียก REST Fabric ส่วนใหญ่ในบทช่วยสอนนี้ส่งส่วนหัว Authorization และ Content-Type เดียวกัน แทนที่จะทําซ้ําในทุกไซต์การโทรบทช่วยสอนนี้จะห่อหุ้มhttpx.ClientFabricClientในส่วนหัวขนาดเล็กที่แนบส่วนหัวโดยอัตโนมัติในขณะที่ยังคงส่งคืนดิบhttpx.Responseเพื่อให้ผู้โทรแต่ละคนสามารถตรวจสอบรหัสสถานะได้ (ตัวอย่างเช่นเพื่อแยกความแตกต่าง201จาก 202)

การห่อแบบ httpx.Client นี้ — แทนที่จะส่งผ่าน headers=_fabric_headers() ทุกไซต์การโทร — ให้ข้อได้เปรียบที่เป็นรูปธรรมสองประการแก่คุณ:

  • ส่วนหัวในที่เดียว: ทุกไซต์การโทรจะรับคําขอล่าสุด _fabric_headers() โดยอัตโนมัติ ดังนั้นจึงไม่สามารถส่งคําขอใหม่โดยไม่ได้ตั้งใจหากไม่มี Authorization ส่วนหัว
  • รหัสสถานะยังคงมองเห็นได้: request() ส่งคืน JSON ดิบ httpx.Response แทน JSON ที่ถอดรหัส ดังนั้นไซต์การโทรจึงยังคงสามารถแยกสาขาตามสถานะ (201 เทียบกับ 202) และตรวจสอบส่วนหัว เช่น Location หรือ Retry-After สําหรับการจัดการ LRO

เพิ่มสิ่งต่อไปนี้หลังจากฟังก์ชันตัวช่วยการรับรองความถูกต้อง:

# =========================================================
# FabricClient (minimal wrapper so call sites stay clean)
# =========================================================

class FabricClient:
    """
    Small wrapper around httpx.Client so we don't repeat headers everywhere.

    Keeps the tutorial behavior:
    - request() returns the raw httpx.Response so the caller can handle 201 vs 202.
    """
    def __init__(self, http_client: httpx.Client):
        self._http = http_client

    def request(self, method: str, url: str, *, json_body=None) -> httpx.Response:
        return self._http.request(method, url, headers=_fabric_headers(), json=json_body)

สร้างฟังก์ชันตัวช่วย LRO

REST API Fabric หลายตัวที่ใช้ในบทช่วยสอนนี้ เช่น Create Lakehouse และ Create Map รองรับ long-running operations (LROs)

API เหล่านี้สามารถส่งคืนการตอบกลับได้หลายรูปแบบ:

  • 201 Created ด้วยเนื้อหาทรัพยากรแบบอินไลน์ (ซิงโครนัส)
  • 202 Accepted โดยมี Location ส่วนหัวชี้ไปที่ URL สถานะการทํางาน (อะซิงโครนัส)
  • 202 Accepted ด้วย x-ms-operation-id ส่วนหัวแทน Location (อะซิงโครนัส, รูปแบบอื่น)
  • 200 OK มี status: "Running" หรือ status: "NotStarted" ขณะทําโพล (ยังอยู่ระหว่างดําเนินการ)
  • 200 OK โดยมี status: "Succeeded" แต่ไม่มีรหัสทรัพยากรในเนื้อหา (สําเร็จ แก้ไขโดยการแสดงรายการและการจับคู่ displayName)

เมื่อต้องการจัดการกับสิ่งเหล่านี้อย่างสม่ําเสมอ ให้สร้างฟังก์ชันตัวช่วยเดียวที่:

  1. ส่งคืนรหัสทรัพยากรทันทีหากการตอบกลับเริ่มต้นมีอยู่แล้ว
  2. มิฉะนั้นจะสํารวจ URL การดําเนินการ (สร้างจาก Location or x-ms-operation-id) โดยใช้ Retry-After.
  3. ปฏิบัติ 200 OK ต่อ status: "Running" / "NotStarted" การที่ยังอยู่ในระหว่างดําเนินการและดําเนินการสํารวจความคิดเห็นต่อไป
  4. เมื่อสําเร็จ จะส่งคืนรหัสทรัพยากรจากเนื้อหา หรือย้อนกลับไปแสดงรายการทรัพยากรและการจับคู่ตาม displayName (ด้วยการลองใหม่) เมื่อเนื้อหาเป็นสถานะเท่านั้น
  5. ใช้ _pbi_headers() เมื่อ URL การสํารวจอยู่บนคลัสเตอร์ Power BI (*.analysis.windows.net) และส่วนหัว Fabric

ตัวช่วยตัวเดียวนี้แทนที่ความต้องการตัวช่วย "แก้ไขตามชื่อ" ต่อทรัพยากร — ทุกcreate_*ฟังก์ชันในบทช่วยสอนนี้เรียก_handle_lroด้วยตัวlist_urlmatch_display_nameช่วยและ .

เพิ่มสิ่งต่อไปนี้หลัง FabricClient ชั้นเรียน

# =========================================================
# LRO handler 
# =========================================================

def _handle_lro(
    client: httpx.Client,
    initial_response: httpx.Response,
    *,
    list_url: str | None = None,
    match_display_name: str | None = None,
    id_field: str = "id",
    max_attempts: int = 10,
    delay: int = 5,
) -> str:
    """
    Handle a Fabric long-running operation (LRO) and return the resource id.

    Supports the response patterns used by Fabric REST APIs:
    - 200/201 with the resource body inline (synchronous).
    - 202 with a `Location` header or `x-ms-operation-id` (asynchronous).
    - 200 with `status: "Running"` / `"NotStarted"` while polling.
    - 200 with `status: "Succeeded"` but no id (resolve by listing and matching `displayName`).

    Polling uses `Retry-After` and switches to a Power BI audience token when
    the operation URL is on `*.analysis.windows.net`.
    """
    # Sync 200/201 with body: return the id immediately.
    if initial_response.status_code in (200, 201):
        try:
            body = initial_response.json() if initial_response.content else {}
        except ValueError:
            body = {}
        if isinstance(body, dict) and body.get(id_field):
            return body[id_field]

    # Location header, with x-ms-operation-id fallback.
    op_url = initial_response.headers.get("Location")
    if not op_url:
        op_id = initial_response.headers.get("x-ms-operation-id")
        if op_id:
            op_url = f"https://api.fabric.microsoft.com/v1/operations/{op_id}"
        else:
            raise RuntimeError(
                f"Missing LRO Location/x-ms-operation-id. "
                f"status={initial_response.status_code} body={initial_response.text[:500]!r}"
            )

    # Audience-aware polling: Power BI cluster endpoints need a different token.
    poll_headers = _pbi_headers() if "analysis.windows.net" in op_url else _fabric_headers()
    retry_after = int(initial_response.headers.get("Retry-After", "5"))

    while True:
        time.sleep(retry_after)
        poll = client.get(op_url, headers=poll_headers)

        if poll.status_code == 202:
            retry_after = int(poll.headers.get("Retry-After", "5"))
            continue

        poll.raise_for_status()
        body = poll.json() if poll.content else {}
        status = body.get("status") if isinstance(body, dict) else None

        if status in ("Running", "NotStarted"):
            retry_after = int(poll.headers.get("Retry-After", "5"))
            continue
        if status == "Failed":
            raise RuntimeError(f"LRO failed. Body: {body}")

        if isinstance(body, dict) and body.get(id_field):
            return body[id_field]

        # Status-only success: list and match by displayName, with retries.
        if status == "Succeeded" and list_url and match_display_name:
            for attempt in range(max_attempts):
                r = client.get(list_url, headers=_fabric_headers())
                r.raise_for_status()
                match = next(
                    (i for i in r.json().get("value", []) if i.get("displayName") == match_display_name),
                    None,
                )
                if match and match.get(id_field):
                    return match[id_field]
                time.sleep(delay)
            raise RuntimeError(
                f"LRO succeeded but resource not visible after retries. "
                f"match_display_name={match_display_name!r}"
            )

        raise RuntimeError(f"LRO completed but no resource id was returned. Body: {body}")

Note

ทรัพยากรที่สร้างขึ้นใหม่อาจไม่ปรากฏขึ้นทันทีเมื่อเรียกใช้ API รายการ เนื่องจากความล่าช้าในการเผยแพร่แบ็กเอนด์ ฟังก์ชันตัวช่วยจะลองใหม่โดยอัตโนมัติจนกว่าทรัพยากรจะปรากฏให้เห็น

ตัวช่วยเพย์โหลดคําจํากัดความ

เมื่อคุณสร้างแผนที่ด้วยคําจํากัดความสาธารณะ REST API สร้างแผนที่คาดหวังให้แต่ละส่วนมีdefinition.partsเพย์โหลดที่เข้ารหัส base64 ด้วย"payloadType": "InlineBase64" ตัวช่วย _json_to_b64 เข้ารหัส Python dict (map.json) ของคุณในรูปแบบนั้น เพื่อให้ create_map สามารถวางลงในเนื้อหาคําขอได้โดยตรง

เพิ่มสิ่งต่อไปนี้หลัง _handle_lro ฟังก์ชัน:

# =========================================================
# Definition payload helper
#
# Encodes map.json as base64 for inline Create map payloads.
# =========================================================

def _json_to_b64(obj: dict) -> str:
    """
    Convert a Python dict to base64-encoded JSON text.

    Fabric Map "Create map with definition inline" requires:
    - definition.parts[].payloadType = InlineBase64
    - definition.parts[].payload     = base64(json(map_json))
    """
    return base64.b64encode(json.dumps(obj).encode("utf-8")).decode("utf-8")

ตัวช่วยอัปโหลด OneLake

OneLake รองรับ ADLS/Blob API และอนุญาตให้กําหนดที่อยู่ตาม GUID สําหรับพื้นที่ทํางานและรายการ:

https://onelake.dfs.fabric.microsoft.com/<workspaceGUID>/<itemGUID>/<path>/<fileName>

เพิ่ม:

# ===============================================================================================
# ONE LAKE UPLOAD HELPERS
# OneLake supports GUID-based addressing:
#   https://onelake.dfs.fabric.microsoft.com/<workspaceGUID>/<itemGUID>/<path>/<fileName> 
# We use the ADLS Gen2 SDK (DataLakeServiceClient) to upload files into the Lakehouse Files area.
# ===============================================================================================

def _onelake_client() -> DataLakeServiceClient:
    """
    Build a DataLakeServiceClient against the OneLake DFS endpoint,
    authenticated with `DefaultAzureCredential`. Used by `_upload_with_retry`
    to write files into the Lakehouse Files area.
    """
    return DataLakeServiceClient(
        account_url="https://onelake.dfs.fabric.microsoft.com",
        credential=DefaultAzureCredential()
    )


def _upload_with_retry(
    workspace_guid: str,
    item_guid: str,
    dest_relative_path: str,
    content: bytes,
    attempts: int = 6
) -> None:
    """
    Upload bytes into OneLake at `<workspace GUID>/<item GUID>/<relative path>`.
    Retries with linear backoff because a newly created Lakehouse can
    briefly return errors before its `Files/` area is provisioned.
    """
    service = _onelake_client()
    fs = service.get_file_system_client(file_system=workspace_guid)

    dest_path = f"{item_guid}/{dest_relative_path}".replace("\\", "/")

    last_exc = None
    for i in range(attempts):
        try:
            fs.get_file_client(dest_path).upload_data(content, overwrite=True)
            return
        except Exception as exc:
            last_exc = exc
            time.sleep(2 + i)

    raise RuntimeError(f"Upload failed after {attempts} attempts: {last_exc}")


Tip

คุณสามารถตรวจสอบว่าไฟล์ถูกอัปโหลดสําเร็จโดยการเรียกดูพื้นที่ไฟล์ Lakehouse ในพอร์ทัล Fabric

สร้างฟังก์ชันหลัก

ถัดไป คุณเพิ่มฟังก์ชันหลักที่กําหนดเวิร์กโฟลว์ ทั้งหมดนี้เรียกว่า main().

  1. สร้างเลคเฮ้าส์
  2. อัปโหลด GeoJSON ไปยังเลคเฮาส์
  3. อัปโหลดเครื่องหมาย SVG ที่กําหนดเอง (ไม่บังคับ)
  4. สร้างคําจํากัดความแผนที่ (map.json)
  5. สร้างแผนที่ด้วยคําจํากัดความแบบอินไลน์

สร้างเลคเฮ้าส์

create_lakehouse สร้างเลคเฮาส์ที่จัดเก็บไฟล์ GeoJSON และเครื่องหมาย SVG เสริมที่ใช้โดยแผนที่

ฟังก์ชั่นนี้:

  • ส่ง POST ไปยังปลายทาง Lakehouse REST ด้วย displayName และ description จากการกําหนดค่าของคุณ
  • ส่งการตอบสนองไปยัง _handle_lroซึ่งจัดการการตอบสนองแบบซิงโครนัส (201) อะซิงโครนัส (202/LRO) และสถานะอย่างเดียวอย่างสม่ําเสมอ
  • ส่งคืน Lakehouse ID เพื่อใช้ในขั้นตอนต่อมา

เพิ่มสิ่งต่อไปนี้หลัง _upload_with_retry ฟังก์ชัน:

# =========================================================
# Step 1: Create a Lakehouse
# =========================================================

def create_lakehouse(client: httpx.Client, fabric: FabricClient, cfg: Config) -> str:
    """
    Create a Lakehouse and return its item ID.
    """
    lakehouse_url = f"https://api.fabric.microsoft.com/v1/workspaces/{cfg.workspace_id}/lakehouses"
    lakehouse_payload = {
        "displayName": cfg.lakehouse_display_name,
        "description": cfg.lakehouse_description
    }

    lh_resp = fabric.request("POST", lakehouse_url, json_body=lakehouse_payload)

    lakehouse_id = _handle_lro(
        client,
        lh_resp,
        list_url=lakehouse_url,
        match_display_name=cfg.lakehouse_display_name,
    )

    print("Lakehouse created. Lakehouse ID:", lakehouse_id)
    return lakehouse_id

อัปโหลด GeoJSON ไปยังเลคเฮาส์

upload_geojson อัปโหลดไฟล์ GeoJSON ในเครื่องไปยังพื้นที่ Lakehouse Files ซึ่งจะกลายเป็นแหล่งข้อมูลเชิงพื้นที่ที่แผนที่อ่านในเวลาที่แสดงผล

นี่เป็นขั้นตอนแรกที่ข้ามจากระนาบควบคุม Fabric (REST) ไปยังระนาบข้อมูล OneLake (ADLS Gen2) ฟังก์ชันจะอ่านไฟล์โลคัลลงในหน่วยความจําและมอบหมายให้ _upload_with_retryซึ่งดําเนินการอัปโหลด DFS แบบแบ่งกลุ่มและลองใหม่ในข้อผิดพลาดชั่วคราว

เพิ่มสิ่งต่อไปนี้หลัง create_lakehouse ฟังก์ชัน:

# =========================================================
# Step 2: Upload GeoJSON to the Lakehouse
# =========================================================

def upload_geojson(cfg: Config, lakehouse_id: str) -> None:
    """
    Upload the local GeoJSON file to the Lakehouse Files area at
    `cfg.geojson_relative_path` using the OneLake DFS endpoint.
    """
    _upload_with_retry(
        workspace_guid=cfg.workspace_id,
        item_guid=lakehouse_id,
        dest_relative_path=cfg.geojson_relative_path,
        content=cfg.local_geojson_path.read_bytes()
    )
    print("Uploaded GeoJSON to:", cfg.geojson_relative_path)

อัปโหลดเครื่องหมาย SVG ที่กําหนดเอง

upload_svg_marker อัปโหลดไอคอน SVG ที่กําหนดเองลงในเลคเฮาส์เดียวกัน เพื่อให้แผนที่สามารถแสดงคุณลักษณะแต่ละรายการด้วยเครื่องหมายนั้นแทนที่จะเป็นไอคอนในตัว ขั้นตอนนี้เป็นทางเลือกและรั้วรอบขอบชิดโดย cfg.use_custom_svg_marker — เมื่อธงเป็น Falseฟังก์ชันจะส่งคืนทันทีและแผนที่จะกลับไปที่เครื่องหมายในตัว

เช่นเดียวกับupload_geojsonฟังก์ชันนี้มอบหมายการอัปโหลดจริงให้กับ_upload_with_retry

เพิ่มสิ่งต่อไปนี้หลัง upload_geojson ฟังก์ชัน:

# =========================================================
# Step 3: Upload a custom SVG marker (optional)
# =========================================================

def upload_svg_marker(cfg: Config, lakehouse_id: str) -> None:
    """
    Upload a custom SVG marker to the Lakehouse at
    `cfg.svg_relative_path` when `cfg.use_custom_svg_marker` is True;
    otherwise return without uploading.
    """
    if not cfg.use_custom_svg_marker:
        return

    _upload_with_retry(
        workspace_guid=cfg.workspace_id,
        item_guid=lakehouse_id,
        dest_relative_path=cfg.svg_relative_path,
        content=cfg.starbucks_marker_svg.encode("utf-8")
    )
    print("Uploaded custom SVG marker to:", cfg.svg_relative_path)

Tip

เครื่องหมาย SVG ปรับขนาดได้อย่างหมดจดในระดับการซูมและ DPI ของหน้าจอ ซึ่งทําให้เหมาะอย่างยิ่งสําหรับไอคอนแผนที่

สร้าง map.json

build_map_json สร้างและส่งคืนเพย์โหลด map.json ที่กําหนดเนื้อหาของ Fabric Map เพย์โหลดเป็นไปตามสคีมาข้อกําหนดของรายการแผนที่และประกอบด้วยสี่ส่วน: dataSources (ที่มาของข้อมูล) iconSources (เครื่องหมายที่กําหนดเองเพิ่มเติม) layerSources (สิ่งที่อ่านและความถี่) และ layerSettings (วิธีแสดงผลลัพธ์บนแผนที่)

สําหรับบทช่วยสอนนี้ ให้dataSourcesชี้ไปที่ Lakehouse (itemType: "Lakehouse") ที่สร้างขึ้นก่อนหน้านี้ และรายการเดียวคือlayerSourcesเลเยอร์ไฟล์ GeoJSON (type: "geojson") ที่อ่านไฟล์ที่คุณอัปโหลดผ่านrelativePath refreshIntervalMs ถูกตั้งค่าเป็น 0 เนื่องจากไฟล์ต้นฉบับเป็นแบบคงที่ — แผนที่จะแสดงไฟล์เพียงครั้งเดียวและไม่สํารวจการเปลี่ยนแปลง

รายการที่ layerSettings ตรงกันจะแสดงคุณลักษณะแต่ละรายการเป็น a marker และแสดงคุณสมบัติ GeoJSON name ในคําแนะนําเครื่องมือ เมื่อcfg.use_custom_svg_markerเป็น TrueiconSources จะมีการเพิ่มรายการที่อ้างอิง SVG ที่คุณอัปโหลด และเลเยอร์iconOptions.imageจะใช้คีย์<layerSettingId>:<iconId>คอมโพสิตเพื่อผูกเครื่องหมายกับไอคอนนั้น เมื่อเป็น Falseเลเยอร์จะถอยกลับไปที่เครื่องหมายในตัว (cfg.builtin_icon_name_fallback) ที่จัดสไตล์ด้วยการเติมสีเขียวสตาร์บัคส์

สําหรับข้อมูลเพิ่มเติมเกี่ยวกับข้อกําหนดแผนที่ REST API โปรดดู คําจํากัดความของรายการแผนที่ สําหรับตัวอย่างของ โปรดดูmap.jsonตัวอย่าง MapDetails

เพิ่มสิ่งต่อไปนี้หลัง upload_svg_marker ฟังก์ชัน:

# =========================================================
# Step 4: Build map.json
# =========================================================

def build_map_json(cfg: Config, lakehouse_id: str) -> dict:
    """
    Build and return the map.json payload for the Fabric Map.

    Wires `dataSources` to the Lakehouse created earlier, defines a
    single GeoJSON layer in `layerSources` that reads the uploaded file
    via `cfg.geojson_relative_path` with `refreshIntervalMs: 0` (the
    source is static), and configures `layerSettings` to render each
    feature as a marker. When `cfg.use_custom_svg_marker` is True, adds
    an `iconSources` entry for the uploaded SVG and binds the layer to
    it via a `<layerSettingId>:<iconId>` composite key; otherwise falls
    back to a built-in marker.
    """
    layer_source_id = str(uuid.uuid4())
    layer_setting_id = str(uuid.uuid4())
    icon_source_id = str(uuid.uuid4())

    custom_svg_marker = f"{layer_setting_id}:{icon_source_id}"
    icon_source_name = "Starbucks Marker"

    map_json = {
        "$schema": "https://developer.microsoft.com/json-schemas/fabric/item/map/definition/2.0.0/schema.json",
        "basemap": {},

        "dataSources": [
            {"itemType": "Lakehouse", "workspaceId": cfg.workspace_id, "itemId": lakehouse_id}
        ],

        "iconSources": (
            [
                {
                    "id": icon_source_id,
                    "name": icon_source_name,
                    "type": "svg",
                    "itemId": lakehouse_id,
                    "relativePath": cfg.svg_relative_path
                }
            ] if cfg.use_custom_svg_marker else []
        ),

        "layerSources": [
            {
                "id": layer_source_id,
                "name": "starbucks_seattle_geojson",
                "type": "geojson",
                "itemId": lakehouse_id,
                "relativePath": cfg.geojson_relative_path,
                "refreshIntervalMs": 0
            }
        ],

        "layerSettings": [
            {
                "id": layer_setting_id,
                "name": "Starbucks (Seattle)",
                "sourceId": layer_source_id,
                "options": {
                    "type": "vector",
                    "visible": True,
                    "tooltipKeys": ["name"],
                    "pointLayerType": "marker",

                    "markerOptions": (
                        {
                            "iconOptions": {
                                "image": custom_svg_marker,
                                "anchor": "bottom",
                                "opacity": 1.0,
                                "rotation": 0,
                                "allowOverlap": False,
                                "rotationAlignment": "viewport",
                                "pitchAlignment": "viewport"
                            },
                            "icon": icon_source_id
                        }
                        if cfg.use_custom_svg_marker
                        else
                        {
                            "size": 22,
                            "fillColor": "#006241",
                            "strokeColor": "#FFFFFF",
                            "strokeWidth": 2,
                            "icon": cfg.builtin_icon_name_fallback,
                            "iconOptions": {
                                "image": f"{layer_setting_id}:{cfg.builtin_icon_name_fallback}",
                                "anchor": "bottom",
                                "opacity": 1.0,
                                "rotation": 0,
                                "allowOverlap": False,
                                "rotationAlignment": "viewport",
                                "pitchAlignment": "viewport"
                            }
                        }
                    )
                }
            }
        ]
    }

    return map_json


Tip

เคล็ดลับที่เกี่ยวข้องกับคําจํากัดความของแผนที่:

  • คุณสมบัตินี้ image ใช้คีย์รวมในรูปแบบ <layerSettingId>:<iconId> เพื่ออ้างอิงไอคอนสําหรับเลเยอร์ สิ่งนี้เชื่อมโยงการกําหนดค่าการแสดงผลเครื่องหมายกับแหล่งที่มาของไอคอนที่กําหนดไว้ก่อนหน้านี้ในข้อกําหนดแผนที่
  • การตั้งค่า refreshIntervalMs เพื่อ 0 ปิดใช้งานการรีเฟรชอัตโนมัติ วิธีนี้เหมาะสําหรับไฟล์ GeoJSON แบบคงที่ที่จัดเก็บไว้ในเลคเฮาส์

สร้างแผนที่ด้วยคําจํากัดความแบบอินไลน์

create_map สร้างแผนที่โดยการลงรายการบัญชีข้อกําหนดแบบอินไลน์ที่คุณได้ประกอบไว้ และส่งคืนรหัสไอเท็มของแผนที่ใหม่ สําหรับบทช่วยสอนนี้ คําขอมีส่วนที่เข้ารหัส base64 เพียงส่วนเดียว — map.json — ห่อเป็นpayloadType: "InlineBase64"และเข้ารหัสผ่าน_json_to_b64 map.jsonเพย์โหลดอ้างอิงแหล่งข้อมูล Lakehouse อยู่แล้ว และเมื่อมี ไอคอน SVG โดย relativePathดังนั้นเลเยอร์จึงต่อสายอย่างสมบูรณ์โดยการเรียก Create Map โดยไม่ต้องติดตามผลupdateDefinitionไปกลับ หากคุณต้องการตั้งค่าข้อมูลเมตาของรายการที่ไม่ใช่ค่าเริ่มต้นหรือปักหมุด logicalId ที่เป็นมิตรกับ Git คุณจะต้องเพิ่มส่วน .platform ลงในอาร์เรย์ parts เดียวกัน Fabric ใช้ข้อมูลเมตาเริ่มต้นเมื่อละเว้น .platform ซึ่งเป็นสิ่งที่บทช่วยสอนนี้ทํา

สร้างแผนที่ REST API สามารถตอบด้วย 201 Created (ซิงโครนัส, ID แบบอินไลน์), 202 Accepted (LRO แบบอะซิงโครนัสผ่าน Location หรือ x-ms-operation-id) หรือ 200 OK ด้วยเพย์โหลดการเสร็จสมบูรณ์แบบสถานะเท่านั้นที่แผนที่ยังไม่ปรากฏใน List Maps เนื่องจากความล่าช้าในการเผยแพร่แบ็กเอนด์ _handle_lro ครอบคลุมกรณีเหล่านี้ทั้งหมด รวมถึงการแสดงรายการและการจับคู่ตาม displayName ดังนั้นฟังก์ชันนี้จึงมอบหมายการจัดการการตอบกลับแบบเต็มในการเรียกครั้งเดียว

สําหรับข้อมูลเพิ่มเติม โปรดดู ข้อกําหนดของรายการแผนที่

เพิ่มสิ่งต่อไปนี้หลัง build_map_json ฟังก์ชัน:

# =========================================================
# Step 5: Create a map with inline definition
# =========================================================

def create_map(client: httpx.Client, fabric: FabricClient, cfg: Config, map_json: dict) -> str:
    """
    Create the Fabric map with its definition inline and return its item ID.

    Sends a single Create map request whose `parts` array carries one
    base64-encoded payload, `map.json`. The map definition already
    references the Lakehouse data source (and, when present, the SVG
    icon) by `relativePath`, so the layer is wired by the Create Map
    call without a follow-up update. Delegates response handling to
    `_handle_lro`, which covers synchronous, asynchronous, and
    status-only completions.
    """
    create_map_url = f"https://api.fabric.microsoft.com/v1/workspaces/{cfg.workspace_id}/maps"

    create_map_payload = {
        "displayName": cfg.map_display_name,
        "description": cfg.map_description,
        "definition": {
            "parts": [
                {
                    "path": "map.json",
                    "payload": _json_to_b64(map_json),
                    "payloadType": "InlineBase64"
                }
            ]
        }
    }

    map_resp = fabric.request("POST", create_map_url, json_body=create_map_payload)

    return _handle_lro(
        client, map_resp,
        list_url=create_map_url,
        match_display_name=cfg.map_display_name,
    )

ประสานเวิร์กโฟลว์

main เป็นจุดเริ่มต้นเดียวที่เรียกใช้บทช่วยสอนแบบ end-to-end มันสร้างConfigอินสแตนซ์ , เปิดหนึ่งตัวhttpx.Clientที่ใช้ซ้ําในทุกตัวช่วย ห่อเป็น FabricClientจากนั้นเรียกใช้ฟังก์ชันแต่ละขั้นตอนตามลําดับการขึ้นต่อกัน: create_lakehouseupload_geojson (เขียน GeoJSON ไปยัง OneLake ภายใต้ Lakehouse ใหม่) → upload_svg_marker (ไม่บังคับ ทํางานเมื่อcfg.use_custom_svg_markerตั้งค่าเท่านั้น) → build_map_jsoncreate_map

การเรียงลําดับมีความสําคัญเนื่องจากแต่ละขั้นตอนใช้บางสิ่งที่สร้างขึ้นโดยขั้นตอนก่อนหน้านี้ และ upload_geojsonupload_svg_marker ต้องการรหัสรายการ Lakehouse และ build_map_json อ้างอิงการอัปโหลดทั้งสองโดย relativePath เพื่อให้ Create map สามารถแก้ไขได้ในเวลาแสดงผล บล็อก print สุดท้ายจะแสดง Lakehouse ID, รหัสแผนที่ และเส้นทางสัมพัทธ์ของเนื้อหาที่อัปโหลด เพื่อให้คุณสามารถค้นหาได้ในพอร์ทัล Fabric

เพิ่มสิ่งต่อไปนี้หลัง create_map ฟังก์ชัน:

# =========================================================
# main(): orchestrates the full workflow
# =========================================================

def main():
    """
    Orchestrate the tutorial workflow.

    1) Create a Lakehouse
    2) Upload GeoJSON to the Lakehouse
    3) Upload a custom SVG marker (optional)
    4) Build the map definition (map.json)
    5) Create the map with its definition inline
    """
    cfg = Config()

    print("Initializing clients...")
    with httpx.Client(timeout=60) as client:
        fabric = FabricClient(client)

        # Step 1
        lakehouse_id = create_lakehouse(client, fabric, cfg)

        # Step 2
        upload_geojson(cfg, lakehouse_id)

        # Step 3 (optional)
        upload_svg_marker(cfg, lakehouse_id)

        # Step 4
        map_json = build_map_json(cfg, lakehouse_id)

        # Step 5
        map_id = create_map(client, fabric, cfg, map_json)

        print("\nDONE")
        print("Lakehouse ID:", lakehouse_id)
        print("Map ID:", map_id)
        print("GeoJSON layer path:", cfg.geojson_relative_path)
        if cfg.use_custom_svg_marker:
            print("Custom SVG marker path:", cfg.svg_relative_path)


if __name__ == "__main__":
    main()

ณ จุดนี้ การกําหนดค่าและรหัสทั้งหมดได้รับการกําหนดแล้ว

ในขั้นตอนต่อไป คุณเรียกใช้สคริปต์เพื่อสร้าง Lakehouse อัปโหลดข้อมูล และสร้างแผนที่

เรียกใช้แอปพลิเคชัน

Note

ชื่อที่แสดงของเลคเฮาส์และแผนที่ต้องไม่ซ้ํากันภายในพื้นที่ทํางาน ก่อนที่จะเรียกใช้สคริปต์อีกครั้ง ให้ลบรายการที่สร้างขึ้นในการเรียกใช้ครั้งก่อนออกจากพื้นที่ทํางาน Fabric หรือเปลี่ยน lakehouse_display_name / map_display_name ใน Config มิฉะนั้น สร้างการเรียกจะล้มเหลวด้วย409 ItemDisplayNameAlreadyInUse

เรียกใช้สคริปต์ที่:

python create_map_from_geojson.py

หากสคริปต์ทํางานสําเร็จ คุณจะเห็นผลลัพธ์ที่คล้ายกับ:

DONE
Lakehouse ID: <Lakehouse ID>
Map ID: <Map ID>
GeoJSON layer path: Files/vector/starbucks-seattle.geojson
Custom SVG marker path: Files/icons/starbucks-marker.svg

ใน Microsoft Fabric แผนที่ของคุณควรมีลักษณะคล้ายกับสิ่งนี้:

ภาพหน้าจอของ Microsoft Fabric Maps ที่แสดงซีแอตเทิลพร้อมไอคอนเครื่องหมาย Starbucks สีเขียวหลายตัวที่กระจุกตัวอยู่ในย่านใจกลางเมืองแผนที่แสดงถนนและลักษณะทางน้ําที่มีพื้นหลังสีเทาอ่อนแผงเลเยอร์ข้อมูลทางด้านซ้ายแสดงเลเยอร์สตาร์บัคส์ (ซีแอตเทิล)แผนที่มีศูนย์กลางอยู่ที่ตัวเมืองซีแอตเทิล รวมถึงริมน้ําอ่าวเอลเลียต โดยมีเครื่องหมายระบุสถานที่ตั้งของสตาร์บัคส์แต่ละแห่งที่อ้างอิงในไฟล์ GeoJSON บทช่วยสอน

Tip

หากแผนที่ไม่ปรากฏขึ้นทันที ให้รีเฟรชพื้นที่ทํางานหรือรอสักครู่เพื่อให้การเผยแพร่แบ็กเอนด์เสร็จสมบูรณ์

Summary

ในบทช่วยสอนนี้ คุณได้สร้างโซลูชันเชิงพื้นที่อัตโนมัติโดยใช้ Microsoft Fabric Maps และข้อมูล Lakehouse

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

คุณทําสิ่งต่อไปนี้สําเร็จ:

  • อัปโหลดข้อมูลเชิงพื้นที่ไปยัง เลคเฮาส์
  • กําหนดค่าชุดข้อมูลสําหรับการแสดงภาพเชิงพื้นที่
  • สร้างแผนที่ Fabric พร้อมคําจํากัดความแบบอินไลน์
  • เชื่อมต่อแผนที่กับข้อมูล Lakehouse
  • เลเยอร์แผนที่ที่กําหนดค่าเพื่อแสดงคุณลักษณะเชิงพื้นที่

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

  • ข้อมูลจะถูกเก็บไว้ใน OneLake (Lakehouse)
  • แผนที่สืบค้นและแสดงชุดข้อมูลเชิงพื้นที่
  • เลเยอร์ให้ข้อมูลเชิงลึกที่มองเห็นได้เกี่ยวกับข้อมูลทางภูมิศาสตร์

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

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

เมื่อคุณเข้าใจวิธีแสดงภาพข้อมูลเชิงพื้นที่จาก Lakehouse แล้ว คุณสามารถขยายโซลูชันนี้ได้:

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

สําหรับข้อมูลเพิ่มเติมเกี่ยวกับการทํางานกับข้อมูลเชิงพื้นที่และแผนที่ใน Fabric ให้ดู:

สําหรับบทช่วยสอนที่สาธิตการสร้างแผนที่แบบเรียลไทม์โดยใช้ REST API โปรดดู: