Thông tin cập nhật theo thời gian thực

Phần này mô tả cách bạn có thể gửi nội dung cập nhật có tính thời gian của các thực thể khoảng không quảng cáo cho Google. API cập nhật theo thời gian thực cho phép bạn đẩy nội dung cập nhật và xoá các thực thể trong khoảng không quảng cáo Hộp cát hoặc Phát hành công khai gần như theo thời gian thực.

Chức năng này chủ yếu dành cho các nội dung cập nhật mà bạn không thể lường trước được, chẳng hạn như đóng cửa khẩn cấp, xoá các mục khỏi trình đơn hoặc cập nhật giá của một mục trong trình đơn. Những nội dung này phải được phản ánh nhanh chóng trong giao diện người dùng của Google. Nếu không cần phản ánh thay đổi ngay lập tức, bạn có thể sử dụng tính năng cung cấp dữ liệu hàng loạt. Thông tin cập nhật theo thời gian thực được xử lý trong tối đa 5 phút.

Điều kiện tiên quyết

Bạn cần có các mục sau đây trước khi triển khai tính năng cập nhật theo thời gian thực:

  1. API Đặt chỗ trên Maps đã được bật:
    • Trong GCP, hãy chuyển đến API và dịch vụ > Thư viện
    • Tìm kiếm "API Đặt chỗ trên Google Maps"
      Tìm API Đặt chỗ trên Google Maps
    • Tìm thực thể Hộp cát ("Google Maps Booking API (Dev)") rồi nhấp vào Bật
    • Tìm phiên bản Phát hành công khai ("API Đặt chỗ trên Google Maps") rồi nhấp vào Bật
      Bật API Đặt chỗ trên Google Maps
  2. Một tài khoản dịch vụ được tạo với vai trò người chỉnh sửa cho dự án GCP của bạn. Để biết thêm thông tin chi tiết, hãy xem phần Thiết lập tài khoản.
  3. Nguồn cấp dữ liệu sản xuất hoặc hộp cát được lưu trữ và nhập. Để biết thêm thông tin chi tiết, hãy xem phần Quy trình truyền dẫn hàng loạt.
  4. Để xác thực API, bạn nên cài đặt Thư viện ứng dụng Google bằng ngôn ngữ bạn chọn. Sử dụng "https://www.googleapis.com/auth/mapsbooking" làm phạm vi OAuth. Các mã mẫu bên dưới sử dụng các thư viện này. Nếu không, bạn sẽ cần xử lý việc trao đổi mã thông báo theo cách thủ công như mô tả trong phần Sử dụng OAuth 2.0 để truy cập vào API của Google.

Tổng quan

API cập nhật theo thời gian thực hỗ trợ hai loại thao tác. Thao tác đầu tiên là upsert để cập nhật các thực thể hiện có. Toán tử thứ hai là xoá để xoá các thực thể khỏi khoảng không quảng cáo. Cả hai thao tác này đều được thực hiện trên một loạt thực thể được liệt kê trong phần nội dung yêu cầu. Bạn có thể cập nhật tối đa 1.000 thực thể trong một lệnh gọi API. API chấp nhận tất cả các yêu cầu đến và đặt chúng vào hàng đợi để xử lý thêm. Do đó, các yêu cầu RTU được xử lý không đồng bộ.

API cập nhật theo thời gian thực hoạt động trong hai môi trường: hộp cát và môi trường phát hành chính thức. Môi trường hộp cát được dùng để kiểm thử các yêu cầu API và môi trường phát hành chính thức để cập nhật nội dung hiển thị cho người dùng Ordering End-to-End. Tên máy chủ của cả hai môi trường:

  • Hộp cát – partnerdev-mapsbooking.googleapis.com
  • Phát hành chính thức – mapsbooking.googleapis.com

Điểm cuối

API cập nhật theo thời gian thực hiển thị hai điểm cuối để xử lý các yêu cầu đến để cập nhật khoảng không quảng cáo:

  • UPSERT – /v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchPush
  • XOÁ – /v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchDelete

Bạn có thể tìm thấy tham số PARTNER_ID trên Actions Center (Trung tâm hành động) dưới dạng Mã đối tác trên trang Tài khoản và người dùng, như trong ảnh chụp màn hình bên dưới.

Mã đối tác trên Cổng thông tin cho đối tác

Lấy 10000001 làm giá trị của PARTNER_ID làm ví dụ từ ảnh chụp màn hình ở trên, URL đầy đủ để gửi yêu cầu API trong hộp cát và môi trường phát hành công khai sẽ giống như trong các ví dụ bên dưới.

# Sandbox UPSERT
https://partnerdev-mapsbooking.googleapis.com/v1alpha/inventory/partners/10000001/feeds/owg.v2/record:batchPush
# Sandbox DELETE
https://partnerdev-mapsbooking.googleapis.com/v1alpha/inventory/partners/10000001/feeds/owg.v2/record:batchDelete
# Production UPSERT
https://mapsbooking.googleapis.com/v1alpha/inventory/partners/10000001/feeds/owg.v2/record:batchPush
# Production DELETE
https://mapsbooking.googleapis.com/v1alpha/inventory/partners/10000001/feeds/owg.v2/record:batchDelete

Cập nhật thực thể

Để cập nhật các thực thể trong khoảng không quảng cáo, hãy sử dụng điểm cuối UPSERT và gửi yêu cầu POST HTTP. Mỗi yêu cầu POST phải bao gồm tham số PARTNER_ID cùng với tải trọng JSON chứa dữ liệu có cấu trúc của bất kỳ loại thực thể nào được liệt kê trong giản đồ khoảng không quảng cáo.

Tải trọng yêu cầu chèn/cập nhật

Nội dung yêu cầu là một đối tượng JSON có danh sách bản ghi. Mỗi bản ghi tương ứng với một thực thể đang được cập nhật. Tệp này bao gồm trường data_record với tải trọng thực thể được mã hoá bằng Base64 và generation_timestamp cho biết thời gian cập nhật thực thể:

  {
    "records": [
      {
        "data_record":"BASE_64_ENCODED_ENTITY",
        "generation_timestamp":"UPDATE_TIMESTAMP"
      }
    ]
  }

Trong tải trọng trên, hãy thay thế nội dung sau:

  • BASE_64_ENCODED_ENTITY: Chuỗi JSON được mã hoá Base64 của thực thể. JSON thực thể đã giải mã phải có cùng cấu trúc như trong thông số kỹ thuật của nguồn cấp dữ liệu, ví dụ:

    {"@type":"MenuSection","name":"My Updated Menu Section","menuId":{"@id":"10824","displayOrder":1},"@id":"853705"}
  • UPDATE_TIMESTAMP: Hãy nhớ thêm dấu thời gian của thời điểm tạo thực thể trong hệ thống phụ trợ. Dấu thời gian này được dùng để đảm bảo thứ tự chính xác của các bản cập nhật khoảng không quảng cáo. Nếu bạn không thêm trường này, trường này sẽ được đặt thành thời điểm Google nhận được yêu cầu. Khi cập nhật một thực thể thông qua yêu cầu batchPush, trường generation_timestamp sẽ được dùng để tạo phiên bản thực thể. Xem định dạng dự kiến của giá trị thời gian trong giản đồ khoảng không quảng cáo quan hệ.

Mọi yêu cầu cập nhật theo thời gian thực đều phải đáp ứng các điều kiện sau:

  • Kích thước nội dung tải trọng không được vượt quá 5 MB. Tương tự như nguồn cấp dữ liệu hàng loạt, bạn nên xoá khoảng trắng để phù hợp với nhiều dữ liệu hơn.
  • Có thể có tối đa 1.000 thực thể trong một yêu cầu batchPush.

Ví dụ

Ví dụ 1: Cập nhật nhà hàng

Giả sử bạn cần cập nhật gấp số điện thoại của một nhà hàng. Nội dung cập nhật của bạn chứa JSON cho toàn bộ nhà hàng.

Hãy xem xét một nguồn cấp dữ liệu theo lô có dạng như sau:

{
  "@type": "Restaurant",
  "@id": "restaurant12345",
  "name": "Some Restaurant",
  "url": "https://www.provider.com/somerestaurant",
  "telephone": "+16501234570",
  "streetAddress": "345 Spear St",
  "addressLocality": "San Francisco",
  "addressRegion": "CA",
  "postalCode": "94105",
  "addressCountry": "US",
  "latitude": 37.472842,
  "longitude": -122.217144
}
  

Sau đó, nội dung cập nhật theo thời gian thực của bạn bằng HTTP POST sẽ như sau:

JSON

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchPush
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
  "records": [
    {
      "data_record": {
        "@type": "Restaurant",
        "@id": "restaurant12345",
        "name": "Some Restaurant",
        "url": "https://www.provider.com/somerestaurant",
        "telephone": "+16501234570",
        "streetAddress": "345 Spear St",
        "addressLocality": "San Francisco",
        "addressRegion": "CA",
        "postalCode": "94105",
        "addressCountry": "US",
        "latitude": 37.472842,
        "longitude": -122.217144
      }
      "generation_timestamp": "2022-08-19T17:11:10.750Z"
    }
  ]
}
    

Base64

Ví dụ tương tự với tải trọng được mã hoá Base64.

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchPush
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
  "records": [
    {
      "data_record": "eyJAdHlwZSI6IlJlc3RhdXJhbnQiLCJAaWQiOiJyZXN0YXVyYW50MTIzNDUiLCJuYW1lIjoiU29tZSBSZXN0YXVyYW50IiwidXJsIjoiaHR0cHM6Ly93d3cucHJvdmlkZXIuY29tL3NvbWVyZXN0YXVyYW50IiwidGVsZXBob25lIjoiKzE2NTAxMjM0NTcwIiwic3RyZWV0QWRkcmVzcyI6IjM0NSBTcGVhciBTdCIsImFkZHJlc3NMb2NhbGl0eSI6IlNhbiBGcmFuY2lzY28iLCJhZGRyZXNzUmVnaW9uIjoiQ0EiLCJwb3N0YWxDb2RlIjoiOTQxMDUiLCJhZGRyZXNzQ291bnRyeSI6IlVTIiwibGF0aXR1ZGUiOjM3LjQ3Mjg0MiwibG9uZ2l0dWRlIjotMTIyLjIxNzE0NH0="
      "generation_timestamp": "2022-08-19T17:11:10.750Z"
    }
  ]
}
    

Ví dụ 2: Cập nhật nhiều nhà hàng

Để cập nhật hai thực thể nhà hàng trong một lệnh gọi API, yêu cầu POST qua HTTP sẽ như sau:

JSON

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchPush
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
  "records": [
    {
      "data_record": {
        "@type": "Restaurant",
        "@id": "restaurant12345",
        "name": "Some Restaurant",
        "url": "https://www.provider.com/somerestaurant",
        "telephone": "+16501235555",
        "streetAddress": "345 Spear St",
        "addressLocality": "San Francisco",
        "addressRegion": "CA",
        "postalCode": "94105",
        "addressCountry": "US",
        "latitude": 37.472842,
        "longitude": -122.217144
      },
      "generation_timestamp": "2022-08-19T17:11:10.850Z"
    },
    {
      "data_record": {
        "@type": "Restaurant",
        "@id": "restaurant123",
        "name": "Some Other Restaurant",
        "url": "https://www.provider.com/someotherrestaurant",
        "telephone": "+16501231235",
        "streetAddress": "385 Spear St",
        "addressLocality": "San Mateo",
        "addressRegion": "CA",
        "postalCode": "94115",
        "addressCountry": "US"
      },
      "generation_timestamp": "2022-08-19T17:11:10.850Z"
    }
  ]
}
    

Base64

Ví dụ tương tự với tải trọng được mã hoá Base64.

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchPush
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
  "records": [
    {
      "data_record": "eyJAdHlwZSI6IlJlc3RhdXJhbnQiLCJAaWQiOiJyZXN0YXVyYW50MTIzNDUiLCJuYW1lIjoiU29tZSBSZXN0YXVyYW50IiwidXJsIjoiaHR0cHM6Ly93d3cucHJvdmlkZXIuY29tL3NvbWVyZXN0YXVyYW50IiwidGVsZXBob25lIjoiKzE2NTAxMjM1NTU1Iiwic3RyZWV0QWRkcmVzcyI6IjM0NSBTcGVhciBTdCIsImFkZHJlc3NMb2NhbGl0eSI6IlNhbiBGcmFuY2lzY28iLCJhZGRyZXNzUmVnaW9uIjoiQ0EiLCJwb3N0YWxDb2RlIjoiOTQxMDUiLCJhZGRyZXNzQ291bnRyeSI6IlVTIiwibGF0aXR1ZGUiOjM3LjQ3Mjg0MiwibG9uZ2l0dWRlIjotMTIyLjIxNzE0NH0=",
      "generation_timestamp": "2022-08-19T17:11:10.850Z"
    },
    {
      "data_record": "eyJAdHlwZSI6IlJlc3RhdXJhbnQiLCJAaWQiOiJyZXN0YXVyYW50MTIzIiwibmFtZSI6IlNvbWUgT3RoZXIgUmVzdGF1cmFudCIsInVybCI6Imh0dHBzOi8vd3d3LnByb3ZpZGVyLmNvbS9zb21lcmVzdGF1cmFudCIsInRlbGVwaG9uZSI6IisxNjUwMTIzMTIzNSIsInN0cmVldEFkZHJlc3MiOiIzODUgU3BlYXIgU3QiLCJhZGRyZXNzTG9jYWxpdHkiOiJTYW4gTWF0ZW8iLCJhZGRyZXNzUmVnaW9uIjoiQ0EiLCJwb3N0YWxDb2RlIjoiOTQxMTUiLCJhZGRyZXNzQ291bnRyeSI6IlVTIn0=",
      "generation_timestamp": "2022-08-19T17:11:10.850Z"
    }
  ]
}
    

Ví dụ 3: Cập nhật giá của một món ăn

Giả sử bạn cần thay đổi giá của một món trong thực đơn.

Hãy xem xét một nguồn cấp dữ liệu theo lô có dạng như sau:

{
  "@type": "MenuItemOffer",
  "@id": "menuitemoffer6680262",
  "sku": "offer-cola",
  "menuItemId": "menuitem896532",
  "price": 2,
  "priceCurrency": "USD"
}

Sau đó, nội dung cập nhật theo thời gian thực của bạn qua POST sẽ như sau:

JSON

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchPush
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
  "records": [
    {
      "data_record": {
        "@type": "MenuItemOffer",
        "@id": "menuitemoffer6680262",
        "sku": "offer-cola",
        "menuItemId": "menuitem896532",
        "price": 2,
        "priceCurrency": "USD"
      },
      "generation_timestamp": "2022-08-19T17:20:10Z"
    }
  ]
}
    

Base64

Ví dụ tương tự với tải trọng được mã hoá Base64.

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchPush
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
  "records": [
    {
      "data_record": "eyJAdHlwZSI6Ik1lbnVJdGVtT2ZmZXIiLCJAaWQiOiJtZW51aXRlbW9mZmVyNjY4MDI2MiIsInNrdSI6Im9mZmVyLWNvbGEiLCJtZW51SXRlbUlkIjoibWVudWl0ZW04OTY1MzIiLCJwcmljZSI6MiwicHJpY2VDdXJyZW5jeSI6IlVTRCJ9",
      "generation_timestamp": "2022-08-19T17:20:10Z"
    }
  ]
}

    

Thêm thực thể

Đừng sử dụng tính năng cập nhật theo thời gian thực để thêm các thực thể mới vì điều này có thể dẫn đến tình trạng dữ liệu không nhất quán. Thay vào đó, hãy sử dụng quy trình nguồn cấp dữ liệu theo lô như mô tả để cung cấp dữ liệu theo lô.

Xoá thực thể

Để xoá các thực thể khỏi khoảng không quảng cáo, hãy sử dụng điểm cuối XOÁ và gửi yêu cầu POST HTTP. Mỗi yêu cầu POST phải bao gồm tham số PARTNER_ID cùng với tải trọng JSON chứa giá trị nhận dạng của bất kỳ thực thể nào trong khoảng không quảng cáo của bạn.

Xoá tải trọng yêu cầu

Nội dung của yêu cầu xoá được cấu trúc tương tự như yêu cầu cập nhật. Tệp này cũng có danh sách bản ghi với các trường data_recorddelete_time:

  {
    "records": [
      {
        "data_record":"BASE_64_ENCODED_REFERENCE",
        "delete_time": "DELETE_TIMESTAMP"
      }
    ]
  }

Trong tải trọng trên, hãy thay thế nội dung sau:

  • BASE_64_ENCODED_REFERENCE: Chuỗi JSON được mã hoá Base64 của tham chiếu đến thực thể đang bị xoá. Một tệp tham chiếu chỉ bao gồm loại thực thể và giá trị nhận dạng, ví dụ: một tệp JSON đại diện cho một tệp tham chiếu đến MenuSection:

    {"@type":"MenuSection","@id":"853705"}
  • DELETE_TIMESTAMP: Hãy nhớ thêm dấu thời gian cho thời điểm thực thể bị xoá trong hệ thống phụ trợ. Dấu thời gian này được dùng để xác định thứ tự áp dụng lệnh xoá cho khoảng không quảng cáo.

Có thể có tối đa 1.000 thực thể trong một yêu cầu batchDelete.

Ví dụ

Ví dụ 1: Xoá hai thực thể MenuItem

Để xoá hai mục trong trình đơn trong một lệnh gọi API, yêu cầu POST qua HTTP sẽ có dạng như sau:

JSON

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchDelete
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
  "records": [
    {
      "data_record": {
        "@type": "MenuItem",
        "@id": "item_1234"
      },
      "delete_time": "2022-08-21T15:23:00.000Z"
    },
    {
      "data_record": {
        "@type": "MenuItem",
        "@id": "item_5678"
      },
      "delete_time": "2022-08-21T15:23:00.000Z"
    }
  ]
}
    

Base64

Ví dụ tương tự với tải trọng được mã hoá Base64.

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchDelete
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
  "records": [
    {
      "data_record": "eyJAdHlwZSI6Ik1lbnVJdGVtIiwiQGlkIjoiaXRlbV8xMjM0In0="
      "delete_time": "2022-08-21T15:23:00.000Z"
    },
    {
      "data_record": "eyJAdHlwZSI6Ik1lbnVJdGVtIiwiQGlkIjoiaXRlbV81Njc4In0="
      "delete_time": "2022-08-21T15:23:00.000Z"
    },
  ]
}
    

Ví dụ 2: Xoá thực thể Restaurant

Hãy xem xét trường hợp bạn muốn xoá một nhà hàng trong nguồn cấp dữ liệu hàng loạt. Bạn chỉ được xoá thực thể nhà hàng. Đừng xoá các thực thể phụ, chẳng hạn như dịch vụ và trình đơn, vì các thực thể này sẽ tự động bị xoá.

Yêu cầu mẫu để xoá một thực thể nhà hàng có mã https://www.provider.com/restaurant/12345:

JSON

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchDelete
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
  "records": [
    {
      "data_record": {
        "@type": "Restaurant",
        "@id": "https://www.provider.com/restaurant/12345"
      },
      "delete_time": "2022-08-19T17:11:10.750Z"
    }
  ]
}
    

Base64

Ví dụ tương tự với tải trọng được mã hoá Base64.

POST v1alpha/inventory/partners/PARTNER_ID/feeds/owg.v2/record:batchDelete
Host: mapsbooking.googleapis.com
Content-Type: application/json
{
  "records": [
    {
      "data_record": "ewogICJAdHlwZSI6ICJSZXN0YXVyYW50IiwKICAiQGlkIjogImh0dHBzOi8vd3d3LnByb3ZpZGVyLmNvbS9yZXN0YXVyYW50LzEyMzQ1Igp9"
      "delete_time": "2022-08-19T17:11:10.750Z"
    }
  ]
}
    

Mã xác thực và phản hồi API

Có hai loại quy trình xác thực được thực hiện trên các lệnh gọi API cập nhật theo thời gian thực:

  • Cấp yêu cầu – Các quy trình xác thực này kiểm tra để đảm bảo rằng tải trọng tuân theo giao thức cập nhật/chèn hoặc xoá và mọi data_record đều chứa cả trường @id@type. Các bước kiểm tra này là đồng bộ và kết quả được trả về trong phần nội dung phản hồi của API. Mã phản hồi 200 và nội dung JSON trống {} có nghĩa là các quy trình xác thực này đã thành công và các thực thể trong yêu cầu đó đã được đưa vào hàng đợi để xử lý. Mã phản hồi khác với 200 có nghĩa là một hoặc nhiều quy trình xác thực này không thành công và toàn bộ yêu cầu đã bị từ chối (bao gồm cả tất cả các thực thể trong tải trọng). Ví dụ: nếu data_record thiếu @type, thì hệ thống sẽ trả về phản hồi lỗi sau:

    {
      "error": {
        "code": 400,
        "message": "Record:{\"@id\":\"2717/86853/DELIVERY\",\"applicableServiceType\":[\"DELIVERY\",\"TAKEOUT\"],\"menuId\":[{\"@id\":\"2717/DELIVERY\",\"displayOrder\":1},{\"@id\":\"2717/TAKEOUT\",\"displayOrder\":2}],\"name\":\"Salad\",\"offeredById\":[\"2717\"]} has following errors: \nThe entity type could not be extracted from the entity value.\n",
        "status": "INVALID_ARGUMENT",
        "details": [
          {
            "@type": "type.googleapis.com/google.rpc.DebugInfo",
            "detail": "[ORIGINAL ERROR] generic::invalid_argument: Failed to parse one or more rtu records. Record:{\"@id\":\"2717/86853/DELIVERY\",\"applicableServiceType\":[\"DELIVERY\",\"TAKEOUT\"],\"menuId\":[{\"@id\":\"2717/DELIVERY\",\"displayOrder\":1},{\"@id\":\"2717/TAKEOUT\",\"displayOrder\":2}],\"name\":\"Salad\",\"offeredById\":[\"2717\"]} has following errors: \nThe entity type could not be extracted from the entity value.\n [google.rpc.error_details_ext] { message: \"Record:{\\\"@id\\\":\\\"2717/86853/DELIVERY\\\",\\\"applicableServiceType\\\":[\\\"DELIVERY\\\",\\\"TAKEOUT\\\"],\\\"menuId\\\":[{\\\"@id\\\":\\\"2717/DELIVERY\\\",\\\"displayOrder\\\":1},{\\\"@id\\\":\\\"2717/TAKEOUT\\\",\\\"displayOrder\\\":2}],\\\"name\\\":\\\"Salad\\\",\\\"offeredById\\\":[\\\"2717\\\"]} has following errors: \\nThe entity type could not be extracted from the entity value.\\n\" }"
          }
        ]
      }
    }
  • Cấp thực thể – Mỗi thực thể trong tải trọng được xác thực theo giản đồ quan hệ. Các vấn đề gặp phải ở giai đoạn xác thực này sẽ không được báo cáo trong phản hồi API. Các thông tin này chỉ được báo cáo trong trang tổng quan Báo cáo RTU.

Hạn mức API

Các bản cập nhật API theo thời gian thực có hạn mức là 1.500 yêu cầu mỗi 60 giây, tức là trung bình 25 yêu cầu mỗi giây. Khi bạn vượt quá hạn mức, Google sẽ phản hồi bằng thông báo lỗi sau:

{
  "error": {
    "code": 429,
    "message": "Insufficient tokens for quota ...",
    "status": "RESOURCE_EXHAUSTED",
    "details": [...]
  }
}

Để xử lý vấn đề này, hãy thử lại lệnh gọi ở khoảng thời gian lớn hơn theo cấp số nhân cho đến khi thành công. Nếu bạn thường xuyên sử dụng hết hạn mức, hãy cân nhắc thêm nhiều thực thể vào một yêu cầu API. Bạn có thể đưa tối đa 1.000 thực thể vào một lệnh gọi API.

Mã mẫu

Dưới đây là một số ví dụ về cách sử dụng API cập nhật theo thời gian thực bằng nhiều ngôn ngữ. Các mẫu này sử dụng Thư viện xác thực của Google để xác thực bằng cách sử dụng tệp khoá tài khoản dịch vụ được tạo trong quá trình Thiết lập tài khoản. Để biết các giải pháp thay thế, hãy tham khảo bài viết Sử dụng OAuth 2.0 cho ứng dụng từ máy chủ đến máy chủ. Cân nhắc sử dụng giản đồ có trong phần Tạo thư viện ứng dụng để tạo mã nguồn cho khoảng không quảng cáo và các loại đối tượng cập nhật theo thời gian thực.

Cập nhật thực thể

Node.js

Mã này sử dụng thư viện xác thực của Google cho Node.js.

/* Sample code for Real-time update batchPush implementation.
 *
 * Required libraries:
 * - google-auth-library
 */

const {JWT} = require('google-auth-library');

// ACTION REQUIRED: Change this to the path of the service account client secret
// file downloaded from the Google Cloud Console.
const serviceAccountJson = require('./service-account.json');

// ACTION REQUIRED: Change this to your Partner ID received from Google.
// The Partner ID is available on the Partner Portal.
const PARTNER_ID = 1234;

const HOST = {
  prod: 'https://mapsbooking.googleapis.com',
  sandbox: 'https://partnerdev-mapsbooking.googleapis.com'
};

// ACTION REQUIRED: Change to 'prod' for production
const ENV = 'sandbox';

// Feed name for Order with Google including the version.
const FEED_NAME = 'owg.v2';

// Endpoint url
const url = `${HOST[ENV]}/v1alpha/inventory/partners/${PARTNER_ID}/feeds/${
    FEED_NAME}/record:batchPush`;

/**
 * Send a Real-time update request to update/insert entities
 */
async function batchUpsert(entities) {
  /**
   * Sign JWT token using private key from service account secret file
   * provided. The client can be created without providing a service account
   * secret file by implementing Application Default Credentials.
   * https://github.com/googleapis/google-auth-library-nodejs
   */
  const client = new JWT({
    email: serviceAccountJson.client_email,
    key: serviceAccountJson.private_key,
    scopes: ['https://www.googleapis.com/auth/mapsbooking'],
  });
  const request = {records: toPushRecords(entities)};
  const body = JSON.stringify(request);
  try {
    const response = await client.request({
      method: 'POST',
      url,
      data: body,
      headers: {'Content-Type': 'application/json'}
    });
    console.log('request body:', body);
    console.log('response status:', response.status);
    console.log(
        'response data:', response.data);  // successful response returns '{}'
  } catch (error) {
    console.log('error:', error);
  }
}

/**
 * Maps array of entities to records for batch push requests
 */
const toPushRecords = (entities) => {
  return entities.map((entity) => {
    // Using dateModified to set generation_timestamp. Defaulting to the
    // current timestamp for records that do not have dateModified.
    const generation_timestamp =
        entity.dateModified ? entity.dateModified : new Date().toISOString();
    return {data_record: btoa(JSON.stringify(entity)), generation_timestamp};
  });
};

// Call batchUpsert with example entities. dateModified is optional and is
// used to hold the actual timestamp when the entity was updated/created.
batchUpsert([
  {
    '@type': 'MenuItemOffer',
    '@id': '6680261',
    'menuItemId': '18931508',
    'price': 15.5,
    'priceCurrency': 'USD',
    'applicableServiceType': ['DELIVERY', 'TAKEOUT'],
    'inventoryLevel': 0,
    'dateModified': '2022-06-19T15:43:50.970Z'
  },
  {
    '@type': 'MenuItemOffer',
    '@id': '6680262',
    'menuItemId': '18931509',
    'price': 25.5,
    'priceCurrency': 'USD',
    'applicableServiceType': ['DELIVERY', 'TAKEOUT'],
    'inventoryLevel': 0,
    'dateModified': '2022-06-19T15:43:50.970Z'
  }
]);

Python

Mã này sử dụng thư viện xác thực của Google cho Python.

"""Sample code for the Real-time update batchPush implementation."""

# Required libraries:
# - google-auth

import base64
import datetime
import json
from google.auth.transport.requests import AuthorizedSession
from google.oauth2 import service_account

# ACTION REQUIRED: Change this to the Partner ID received from Google.
# Partner ID is available on the Partner Portal.
# https://partnerdash.google.com/apps/reservewithgoogle
_PARTNER_ID = '1234'

# ACTION REQUIRED: Change this to the path of the service account client secret
# file downloaded from the Google Cloud Console.
_SERVICE_ACCOUNT_KEY_JSON_FILE = 'service-account-creds.json'

_HOST_MAP = {
    'sandbox': 'https://partnerdev-mapsbooking.googleapis.com',
    'prod': 'https://mapsbooking.googleapis.com'
}

# ACTION REQUIRED: Change to 'prod' for production
_ENV = 'sandbox'

# Feed name for Order with Google including the version.
_FEED_NAME = 'owg.v2'

_ENDPOINT = '{}/v1alpha/inventory/partners/{}/feeds/{}/record:batchPush'.format(
    _HOST_MAP[_ENV], _PARTNER_ID, _FEED_NAME)


def batch_upsert(entities):
  """Makes a batchPush request using the Real-time updates REST service.

  Args:
      entities: The list of entity objects to update or add.
  """

  # Creates credentials by providing a json file. Credentials can also be
  # provided by implementing Application Default Credentials.
  # https://googleapis.dev/python/google-auth/latest/user-guide.html
  credentials = service_account.Credentials.from_service_account_file(
      _SERVICE_ACCOUNT_KEY_JSON_FILE,
      scopes=['https://www.googleapis.com/auth/mapsbooking'])
  authorized_session = AuthorizedSession(credentials)

  # JSON request object
  batch_request = {'records': [create_push_record(x) for x in entities]}
  response = authorized_session.post(_ENDPOINT, json=batch_request)
  print('request body:', json.dumps(batch_request))
  print('response status:', response.status_code)
  print('response data:', response.text)  # successful response returns '{}'


def create_push_record(entity):
  """Creates a record from an entity for batchPush requests.

  Args:
      entity: The entity object to create the record from.

  Returns:
      The constructed record for the batchPush request payload.
  """
  data_bytes = json.dumps(entity).encode('utf-8')
  base64_bytes = base64.b64encode(data_bytes)
  # Using dateModified to set generation_timestamp. Defaulting to the
  # current timestamp for records that do not have dateModified.
  generation_timestamp = entity.dateModified if 'dateModified' in entity else datetime.datetime.now(
  ).strftime('%Y-%m-%dT%H:%M:%S.%fZ')
  return {
      'generation_timestamp': generation_timestamp,
      'data_record': base64_bytes.decode('utf-8')
  }


# Call batch_upsert with example entities. dateModified is optional and is
# used to hold the actual timestamp when the entity was updated/created.
batch_upsert([{
    '@type': 'MenuItemOffer',
    '@id': '6680261',
    'menuItemId': '18931508',
    'price': 15.5,
    'priceCurrency': 'USD',
    'applicableServiceType': ['DELIVERY', 'TAKEOUT'],
    'inventoryLevel': 0,
    'dateModified': '2022-06-19T15:43:50.970Z'
}, {
    '@type': 'MenuItemOffer',
    '@id': '6680262',
    'menuItemId': '18931509',
    'price': 25.5,
    'priceCurrency': 'USD',
    'applicableServiceType': ['DELIVERY', 'TAKEOUT'],
    'inventoryLevel': 0,
    'dateModified': '2022-06-19T15:43:50.970Z'
}])

Java

Mã này sử dụng thư viện xác thực của Google cho Java.

Các mô hình mã nguồn ứng dụng trong gói rtusamples.inventoryrtusamples.realtime được tạo bằng cách làm theo các bước trong phần Tạo thư viện ứng dụng.

/*
 * Required Libraries:
 * - JDK >= 11
 * - google-auth-library-oauth2-http
 */
package rtusamples;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.auth.oauth2.AccessToken;
import com.google.auth.oauth2.GoogleCredentials;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.nio.charset.Charset;
import java.time.Clock;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import rtusamples.inventory.MenuItemOffer;
import rtusamples.inventory.MenuItemOfferType;
import rtusamples.inventory.ServiceTypeElement;
import rtusamples.realtime.BatchPushGenericRecordRequest;
import rtusamples.realtime.GenericRecord;

/** Sample code for Real-time update batchPush implementation. */
public final class BasicPush {
  // ACTION REQUIRED: Change this to your Partner ID received from Google. The Partner ID is
  // available on the Partner Portal.
  private static final long PARTNER_ID = 12345678;

  // ACTION REQUIRED: Change this to the path of the service account client secret file downloaded
  // from the Google Cloud Console.
  private static final String JSON_KEY_FULL_PATH =
      "<path to your JSON credentials>/credentials.json";

  // ACTION REQUIRED: Change this to the endpoint that is needed.
  private static final String ENDPOINT =
      //    "https://partnerdev-mapsbooking.googleapis.com"; // for sandbox
      "https://mapsbooking.googleapis.com"; // for prod

  // Feed name for Order with Google including the version.
  private static final String FEED_NAME = "owg.v2";

  private static final ObjectMapper objectMapper = new ObjectMapper();

  private static final DateTimeFormatter TIMESTAMP_FORMATTER =
      DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[.SSS]'Z'");

  private static final Charset UTF_8 = Charset.forName("UTF-8");

  public static void main(String[] args) throws Exception {

    /**
     * Create credentials from service account secret file. Alternatively, the credentials can be
     * created by implementing Application Default Credentials.
     * https://github.com/googleapis/google-auth-library-java
     */
    // GoogleCredentials sourceCredentials =
    //     GoogleCredentials.getApplicationDefault()
    //         .createScoped(Arrays.asList("https://www.googleapis.com/auth/mapsbooking"));

    // ImpersonatedCredentials credentials =
    //     ImpersonatedCredentials.create(
    //         sourceCredentials,
    //         "fo-test@projectname.iam.gserviceaccount.com",
    //         null,
    //         Arrays.asList("https://www.googleapis.com/auth/mapsbooking"),
    //         300);

    GoogleCredentials credentials =
        GoogleCredentials.fromStream(new FileInputStream(JSON_KEY_FULL_PATH))
            .createScoped(Arrays.asList("https://www.googleapis.com/auth/mapsbooking"));

    // Create example MenuItemOffer entities, dateModified is optional and is used to hold
    // the actual timestamp when the entity was updated/created.
    MenuItemOffer menuItemOfferPizza = new MenuItemOffer();
    menuItemOfferPizza.setID("6680261");
    menuItemOfferPizza.setType(MenuItemOfferType.MENU_ITEM_OFFER);
    menuItemOfferPizza.setMenuItemID("18931508");
    menuItemOfferPizza.setPrice(15.5);
    menuItemOfferPizza.setPriceCurrency("USD");
    menuItemOfferPizza.setApplicableServiceType(
        new ServiceTypeElement[] {ServiceTypeElement.TAKEOUT, ServiceTypeElement.DELIVERY});
    menuItemOfferPizza.setInventoryLevel(0.0);
    menuItemOfferPizza.setDateModified("2022-10-07T13:00:00.000Z");

    MenuItemOffer menuItemOfferSalad = new MenuItemOffer();
    menuItemOfferSalad.setID("6680262");
    menuItemOfferSalad.setType(MenuItemOfferType.MENU_ITEM_OFFER);
    menuItemOfferSalad.setMenuItemID("18931509");
    menuItemOfferSalad.setPrice(25.5);
    menuItemOfferSalad.setPriceCurrency("USD");
    menuItemOfferSalad.setApplicableServiceType(
        new ServiceTypeElement[] {ServiceTypeElement.TAKEOUT, ServiceTypeElement.DELIVERY});
    menuItemOfferSalad.setInventoryLevel(0.0);
    menuItemOfferSalad.setDateModified("2022-10-07T13:00:00.000Z");

    // Example array of MenuItemOffer entities to update.
    List<MenuItemOffer> menuItemOffers = Arrays.asList(menuItemOfferPizza, menuItemOfferSalad);

    // Create list of GenericRecord from menuItemOffers.
    List<GenericRecord> menuItemOfferGenericRecords =
        menuItemOffers.stream()
            .map(
                (menuItemOffer) ->
                    toBatchPushRecord(menuItemOffer, menuItemOffer.getDateModified()))
            .collect(Collectors.toList());

    // List of records to be updated/created.
    List<GenericRecord> recordsToBeUpdated = new ArrayList<>();

    // Add list of menuItemOffer generic records.
    recordsToBeUpdated.addAll(menuItemOfferGenericRecords);

    // Request object that contains all records.
    BatchPushGenericRecordRequest batchPushRequest = new BatchPushGenericRecordRequest();
    batchPushRequest.setRecords(recordsToBeUpdated.toArray(new GenericRecord[0]));

    // Execute batchPush request.
    BasicPush basicPush = new BasicPush();
    basicPush.batchPush(batchPushRequest, credentials);
  }

  public void batchPush(
      BatchPushGenericRecordRequest batchPushRequest, GoogleCredentials credentials)
      throws IOException {

    credentials.refreshIfExpired();
    AccessToken token = credentials.getAccessToken();

    String requestBody = objectMapper.writeValueAsString(batchPushRequest);
    HttpClient client = HttpClient.newHttpClient();
    HttpRequest request =
        HttpRequest.newBuilder()
            .uri(
                URI.create(
                    String.format(
                        "%s/v1alpha/inventory/partners/%s/feeds/%s/record:batchPush",
                        ENDPOINT, PARTNER_ID, FEED_NAME)))
            .header("Content-Type", "application/json")
            .header("Authorization", String.format("Bearer %s", token.getTokenValue()))
            .POST(BodyPublishers.ofString(requestBody))
            .build();

    HttpResponse<String> response = null;
    try {
      response = client.send(request, BodyHandlers.ofString());
      System.out.println("Request body:" + requestBody);
      System.out.println("Response status:" + response.statusCode());
      System.out.println("Response body:" + response.body());
    } catch (IOException | InterruptedException e) {
      e.printStackTrace();
    }
  }

  public static <T> GenericRecord toBatchPushRecord(T entity, String dateModified) {
    GenericRecord genericRecord = new GenericRecord();
    try {
      String json = objectMapper.writeValueAsString(entity);
      genericRecord.setDataRecord(Base64.getEncoder().encodeToString(json.getBytes(UTF_8)));
      // Using dateModified to set generation_timestamp. Defaulting to the
      // current timestamp for records that do not have dateModified.
      String generationTimestamp =
          Optional.ofNullable(dateModified)
              .orElse(OffsetDateTime.now(Clock.systemUTC()).format(TIMESTAMP_FORMATTER));
      genericRecord.setGenerationTimestamp(generationTimestamp);
    } catch (JsonProcessingException e) {
      System.out.println(e.getMessage());
    }
    return genericRecord;
  }
}

Xoá thực thể

Node.js

Mã này sử dụng thư viện xác thực của Google cho Node.js.

/* Sample code for Real-time update batchDelete implementation.
 *
 * Required libraries:
 * - google-auth-library
 */

const {JWT} = require('google-auth-library');

// ACTION REQUIRED: Change this to the path of the service account client secret
// file downloaded from the Google Cloud Console.
const serviceAccountJson = require('./service-account.json');

// ACTION REQUIRED: Change this to your Partner ID received from Google.
// The Partner ID is available on the Partner Portal.
const PARTNER_ID = 1234;

const HOST = {
  prod: 'https://mapsbooking.googleapis.com',
  sandbox: 'https://partnerdev-mapsbooking.googleapis.com'
};

// ACTION REQUIRED: Change to 'prod' for production
const ENV = 'sandbox';

// Feed name for Order with Google including the version.
const FEED_NAME = 'owg.v2';

// Endpoint url
const url = `${HOST[ENV]}/v1alpha/inventory/partners/${PARTNER_ID}/feeds/${
    FEED_NAME}/record:batchDelete`;


/**
 * Send a Real-time update request to delete entities
 */
async function batchDelete(entities) {
  try {
    /**
     * Sign JWT token using private key from service account secret file
     * provided. The client can be created without providing a service account
     * secret file by implementing Application Default Credentials.
     * https://github.com/googleapis/google-auth-library-nodejs
     */
    const client = new JWT({
      email: serviceAccountJson.client_email,
      key: serviceAccountJson.private_key,
      scopes: ['https://www.googleapis.com/auth/mapsbooking'],
    });
    const request = {
      records: toDeleteRecords(entities)
    };
    const body = JSON.stringify(request);
    try {
      const response = await client.request({
        method: 'POST',
        url,
        data: body,
        headers: {'Content-Type': 'application/json'}
      });
      console.log('request body:', body);
      console.log('response status:', response.status);
      console.log('response data:', response.data);  // successful response returns '{}'
    } catch (error) {
      console.log('error:', error);
    }
  }

  /**
   * Maps array of entities to records for batch delete requests
   */
  const toDeleteRecords = (entities) => {
    return entities.map((entity) => {
      // Using dateModified to set delete_time. Defaulting to the current
      // timestamp for records that do not have dateModified.
      const delete_time =
          entity.dateModified ? entity.dateModified : new Date().toISOString();
      return {data_record: btoa(JSON.stringify(entity)), delete_time};
    });
  };

  // Call batchDelete with example entities. dateModified is optional and is
  // used to hold the actual timestamp when the entity was deleted.
  batchDelete([
    {
      '@type': 'Menu',
      '@id': '853706',
      'dateModified': '2022-06-19T15:43:50.970Z'
    },
    {
      '@type': 'Menu',
      '@id': '853705',
      'dateModified': '2022-06-19T15:13:00.280Z'
    }
  ]);

Python

Mã này sử dụng thư viện xác thực của Google cho Python.

"""Sample code for the Real-time update batchDelete implementation."""

# Required libraries:
# - google-auth

import base64
import datetime
import json
from google.auth.transport.requests import AuthorizedSession
from google.oauth2 import service_account

# ACTION REQUIRED: Change this to the Partner ID received from Google.
# Partner ID is available on the Partner Portal.
# https://partnerdash.google.com/apps/reservewithgoogle
_PARTNER_ID = '1234'

# ACTION REQUIRED: Change this to the path of the service account client secret
# file downloaded from the Google Cloud Console.
_SERVICE_ACCOUNT_KEY_JSON_FILE = 'service-account-creds.json'

_HOST_MAP = {
    'sandbox': 'https://partnerdev-mapsbooking.googleapis.com',
    'prod': 'https://mapsbooking.googleapis.com'
}

# ACTION REQUIRED: Change to 'prod' for production
_ENV = 'sandbox'

# Feed name for Order with Google including the version.
_FEED_NAME = 'owg.v2'

_ENDPOINT = '{}/v1alpha/inventory/partners/{}/feeds/{}/record:batchDelete'.format(
    _HOST_MAP[_ENV], _PARTNER_ID, _FEED_NAME)


def batch_delete(entities):
  """Makes a batch delete request using the Real-time updates REST service.

  Args:
      entities: The list of entity objects to delete.
  """

  # Creates credentials by providing a json file. Credentials can also be
  # provided by implementing Application Default Credentials.
  # https://googleapis.dev/python/google-auth/latest/user-guide.html
  credentials = service_account.Credentials.from_service_account_file(
      _SERVICE_ACCOUNT_KEY_JSON_FILE,
      scopes=['https://www.googleapis.com/auth/mapsbooking'])
  authorized_session = AuthorizedSession(credentials)

  # JSON request object
  batch_request = {'records': [create_delete_record(x) for x in entities]}
  response = authorized_session.post(_ENDPOINT, json=batch_request)
  print('request body:', json.dumps(batch_request))
  print('response status:', response.status_code)
  print('response data:', response.text)  # successful response returns '{}'


def create_delete_record(entity):
  """Creates a record from an entity for batchDelete requests.

  Args:
    entity: The entity object to create the record from.

  Returns:
    The constructed record for the batchDelete request payload.
  """
  data_bytes = json.dumps(entity).encode('utf-8')
  base64_bytes = base64.b64encode(data_bytes)
  # Using dateModified to set delete_time. Defaulting to the current
  # timestamp for records that do not have dateModified.
  delete_time = entity.dateModified if 'dateModified' in entity else datetime.datetime.now(
  ).strftime('%Y-%m-%dT%H:%M:%S.%fZ')
  return {
      'delete_time': delete_time,
      'data_record': base64_bytes.decode('utf-8')
  }


# Call batch_delete with example entities. dateModified is optional and is
# used to hold the actual timestamp when the entity was deleted.
batch_delete([{
    '@type': 'Menu',
    '@id': '853706',
    'dateModified': '2022-06-19T13:10:00.000Z'
}, {
    '@type': 'Menu',
    '@id': '853705',
    'dateModified': '2022-06-19T13:30:10.000Z'
}])

Java

Mã này sử dụng thư viện xác thực của Google cho Java.

Các mô hình mã nguồn ứng dụng trong gói rtusamples.inventoryrtusamples.realtime được tạo bằng cách làm theo các bước trong phần Tạo thư viện ứng dụng.

/*
 * Required Libraries:
 * - JDK >= 11
 * - google-auth-library-oauth2-http
 */
package rtusamples;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.auth.oauth2.AccessToken;
import com.google.auth.oauth2.GoogleCredentials;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.nio.charset.Charset;
import java.time.Clock;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import rtusamples.inventory.Menu;
import rtusamples.inventory.MenuType;
import rtusamples.realtime.BatchDeleteGenericRecordsRequest;
import rtusamples.realtime.GenericDeleteRecord;

/** Sample code for the Real-time update batchDelete implementation. */
public final class BasicDelete {
  // ACTION REQUIRED: Change this to your Partner ID received from Google. The Partner ID is
  // available on the Partner Portal.
  private static final long PARTNER_ID = 123456789;

  // ACTION REQUIRED: Change this to the path of the service account client secret file downloaded
  // from the Google Cloud Console.
  private static final String JSON_KEY_FULL_PATH =
      "<path to your JSON credentials>/credentials.json";

  // ACTION REQUIRED: Change this to the endpoint that is needed.
  private static final String ENDPOINT =
      "https://partnerdev-mapsbooking.googleapis.com"; // for sandbox
  // "https://mapsbooking.googleapis.com" // for prod

  // Feed name for Order with Google including the version.
  private static final String FEED_NAME = "owg.v2";

  private static final ObjectMapper objectMapper = new ObjectMapper();

  private static final DateTimeFormatter TIMESTAMP_FORMATTER =
      DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[.SSS]'Z'");

  private static final Charset UTF_8 = Charset.forName("UTF-8");

  public static void main(String[] args) throws Exception {

    /**
     * Create credentials from service account secret file. Alternatively, the credentials can be
     * created by implementing Application Default Credentials.
     * https://github.com/googleapis/google-auth-library-java
     */
    // GoogleCredentials sourceCredentials =
    //     GoogleCredentials.getApplicationDefault()
    //         .createScoped(Arrays.asList("https://www.googleapis.com/auth/mapsbooking"));

    // ImpersonatedCredentials credentials =
    //     ImpersonatedCredentials.create(
    //         sourceCredentials,
    //         "fo-test@projectname.iam.gserviceaccount.com",
    //         null,
    //         Arrays.asList("https://www.googleapis.com/auth/mapsbooking"),
    //         300);

    GoogleCredentials credentials =
        GoogleCredentials.fromStream(new FileInputStream(JSON_KEY_FULL_PATH))
            .createScoped(Arrays.asList("https://www.googleapis.com/auth/mapsbooking"));

    // Create example Menu entities, dateModified is optional and is used to hold
    // the actual timestamp when the entity was deleted.
    Menu menuLunch = new Menu();
    menuLunch.setID("853705");
    menuLunch.setType(MenuType.MENU);
    menuLunch.setDateModified("2022-09-19T13:10:00.000Z");

    Menu menuDinner = new Menu();
    menuDinner.setID("853706");
    menuDinner.setType(MenuType.MENU);
    menuDinner.setDateModified("2022-09-19T13:13:10.000Z");

    // Example array of Menu entities to update.
    List<Menu> menus = Arrays.asList(menuLunch, menuDinner);

    // Create list of GenericDeleteRecord from menus.
    List<GenericDeleteRecord> menuGenericDeleteRecords =
        menus.stream()
            .map((menu) -> toBatchDeleteRecord(menu, menu.getDateModified()))
            .collect(Collectors.toList());

    // List of records to be deleted.
    List<GenericDeleteRecord> recordsToBeDeleted = new ArrayList<>();

    // Add list of menu generic records.
    recordsToBeDeleted.addAll(menuGenericDeleteRecords);

    // Request object that contains all records.
    BatchDeleteGenericRecordsRequest batchDeleteRequest = new BatchDeleteGenericRecordsRequest();
    batchDeleteRequest.setRecords(recordsToBeDeleted.toArray(new GenericDeleteRecord[0]));

    // Execute batchDelete request.
    BasicDelete basicDelete = new BasicDelete();
    basicDelete.batchDelete(batchDeleteRequest, credentials);
  }

  public void batchDelete(
      BatchDeleteGenericRecordsRequest batchDeleteRequest, GoogleCredentials credentials)
      throws IOException {

    credentials.refreshIfExpired();
    AccessToken token = credentials.getAccessToken();

    String requestBody = objectMapper.writeValueAsString(batchDeleteRequest);
    HttpClient client = HttpClient.newHttpClient();
    HttpRequest request =
        HttpRequest.newBuilder()
            .uri(
                URI.create(
                    String.format(
                        "%s/v1alpha/inventory/partners/%s/feeds/%s/record:batchDelete",
                        ENDPOINT, PARTNER_ID, FEED_NAME)))
            .header("Content-Type", "application/json")
            .header("Authorization", String.format("Bearer %s", token.getTokenValue()))
            .POST(BodyPublishers.ofString(requestBody))
            .build();

    HttpResponse<String> response = null;
    try {
      response = client.send(request, BodyHandlers.ofString());
      System.out.println("Request body:" + requestBody);
      System.out.println("Response status:" + response.statusCode());
      System.out.println("Response body:" + response.body());
    } catch (IOException | InterruptedException e) {
      e.printStackTrace();
    }
  }

  public static <T> GenericDeleteRecord toBatchDeleteRecord(T entity, String dateModified) {
    GenericDeleteRecord genericRecord = new GenericDeleteRecord();
    try {
      String json = objectMapper.writeValueAsString(entity);
      genericRecord.setDataRecord(Base64.getEncoder().encodeToString(json.getBytes(UTF_8)));
      // Using dateModified to set delete_time. Defaulting to the current
      // timestamp for records that do not have dateModified.
      String deleteTime =
          Optional.ofNullable(dateModified)
              .orElse(OffsetDateTime.now(Clock.systemUTC()).format(TIMESTAMP_FORMATTER));
      genericRecord.setDeleteTime(deleteTime);
    } catch (JsonProcessingException e) {
      System.out.println(e.getMessage());
    }
    return genericRecord;
  }
}

Trường hợp sử dụng

Các trường hợp sử dụng sau đây là ví dụ về nội dung cập nhật theo thời gian thực, cập nhật nguồn cấp dữ liệu hàng loạt và nội dung ở cấp cao trong lệnh gọi API:

Trường hợp Thực thể cần cập nhật Nội dung mô tả và hiệu ứng
Tắt dịch vụ Service

Bạn cần tắt một dịch vụ vì lý do ngoài dự kiến.

Cập nhật theo thời gian thực: Cập nhật thực thể Service trong câu hỏi bằng cách đặt thuộc tính isDisabled thành true, nhưng giữ nguyên các thuộc tính khác.

Nguồn cấp dữ liệu đầy đủ: Hãy nhớ cập nhật thực thể từ nguồn cấp dữ liệu đầy đủ để đặt isDisabled thành true trước lần tìm nạp tiếp theo của Google, nếu không, thực thể sẽ được bật lại.

Mặt hàng cụ thể đã hết hàng MenuItemOffer Cập nhật theo thời gian thực: Gửi thực thể MenuItemOffer đóng gói với inventoryLevel được đặt thành 0 cho MenuItem đã cho và tất cả dữ liệu khác không thay đổi.
Thay đổi giá của món ăn trong thực đơn MenuItemOffer Cập nhật theo thời gian thực: Gửi thực thể MenuItemOffer đóng gói với price được đặt thành giá đã cập nhật cho MenuItem đã cho và tất cả dữ liệu khác không thay đổi.

Thêm thực thể cấp cao nhất mới

Chỉ áp dụng cho thực thể thuộc loại Menu, RestaurantService.

Menu, Restaurant, Service

Ví dụ: bạn cần thêm một thực đơn mới vào nhà hàng.

Nguồn cấp dữ liệu đầy đủ: Thêm thực thể vào nguồn cấp dữ liệu và đợi quá trình truyền dẫn hàng loạt.

Xoá vĩnh viễn thực thể cấp cao nhất

Chỉ áp dụng cho thực thể thuộc loại Menu, RestaurantService.

Menu, Restaurant, Service

Cập nhật theo thời gian thực: Gửi yêu cầu xoá rõ ràng.

Nguồn cấp dữ liệu đầy đủ: Hãy nhớ xoá thực thể khỏi nguồn cấp dữ liệu đầy đủ trước lần tìm nạp tiếp theo của Google, nếu không, thực thể sẽ được thêm lại.

Thêm khu vực phân phối mới trong một Service cụ thể ServiceArea Nguồn cấp dữ liệu theo lô: Gửi thực thể ServiceArea có liên quan với tất cả các trường nguyên vẹn, như bạn thường làm trong nguồn cấp dữ liệu đầy đủ, với khu vực phân phối mới được chỉ định trong polygon, geoRadius hoặc postalCode.
Cập nhật thời gian giao hàng dự kiến trong Service ServiceHours Nguồn cấp dữ liệu hàng loạt: Gửi ServiceHours giống như trong nguồn cấp dữ liệu, ngoại trừ leadTimeMin được cập nhật tương ứng.
Cập nhật giá giao hàng trong Service Fee Nguồn cấp dữ liệu hàng loạt: Gửi Fee phân phối đầy đủ với price đã cập nhật.
Cập nhật giờ giao hàng hoặc giờ bán mang đi trong Service ServiceHours Nguồn cấp dữ liệu theo lô: Gửi ServiceHours giống như trong nguồn cấp dữ liệu, ngoại trừ các thuộc tính openscloses được cập nhật tương ứng.
Service (thay đổi số lượng đơn đặt hàng tối thiểu) Fee Nguồn cấp dữ liệu theo lô: Gửi Fee đầy đủ với minPrice đã cập nhật
Xoá MenuItem vĩnh viễn Menu Nguồn cấp dữ liệu theo lô: Gửi MenuItem giống như trong nguồn cấp dữ liệu, nhưng parentMenuSectionId trống.

Thời gian xử lý cho công việc hàng loạt và nội dung cập nhật theo thời gian thực

Một thực thể được cập nhật hoặc xoá thông qua nguồn cấp dữ liệu theo lô sẽ được xử lý trong vòng 2 giờ, trong khi một thực thể được cập nhật thông qua tính năng cập nhật theo thời gian thực sẽ được xử lý trong vòng 5 phút. Thực thể lỗi thời sẽ bị xoá sau 14 ngày.

Bạn có thể gửi cho Google:

  • Nhiều công việc theo lô mỗi ngày để luôn cập nhật kho hàng, HOẶC
  • Một công việc theo lô mỗi ngày và thông tin cập nhật theo thời gian thực để kho hàng luôn được cập nhật.