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ó giới hạn về thời gian của kho hàng thực thể vào Google. API cập nhật theo thời gian thực cho phép bạn đẩy thông tin cập nhật và xoá trong khoảng không quảng cáo chính thức hoặc Hộp cát của bạn gần như theo thời gian thực.

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

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

Bạn phải cung cấp những mục sau trước khi triển khai tính năng cập nhật theo thời gian thực:

  1. Đã bật API Đặt chỗ trên Maps:
    • Trong GCP, hãy chuyển đến phần API và Dịch vụ > Thư viện
    • Tìm kiếm “API Đặt chỗ trên Google Maps”
      Xác định vị trí API Đặt chỗ trên Google Maps
    • Tìm phiên bản Hộp cát (“API Đặt chỗ của Google Maps (Nhà phát triển)”) rồi nhấp vào Bật
    • Tìm phiên bản chính thức (“API Đặt chỗ của 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 đối với dự án GCP của bạn. Cho chi tiết khác, xem Thiết lập tài khoản.
  3. Nguồn cấp dữ liệu sản xuất hoặc nguồn cấp dữ liệu hộp cát được lưu trữ và nhập. Để biết thêm thông tin, hãy xem phần Nhập 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ữ của lựa chọn. Sử dụng “https://www.googleapis.com/auth/mapsbooking” làm OAuth phạm vi. 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 cần xử lý các hoạt động đổi mã thông báo theo cách thủ công như mô tả trong Sử dụng OAuth 2.0 để truy cập Google API.

Tổng quan

API Cập nhật theo thời gian thực hỗ trợ 2 loại thao tác. Thao tác đầu tiên là trình cập nhật và chèn để cập nhật các thực thể hiện có. Chiến lược phát hành đĩa đơn thao tác thứ hai là xoá để xoá các thực thể khỏi khoảng không quảng cáo của bạn. Cả hai các thao tác đượ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ể chỉ trong một lệnh gọi API. API chấp nhận tất cả các yêu cầu được gửi đến và đưa chúng vào hàng đợi để xử lý thêm. Do đó, 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à phiên bản 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à quá trình sản xuất để cập nhật nội dung hiển thị cho người dùng Đặt hàng hai đầu. 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 công khai – mapsbooking.googleapis.com

Điểm cuối

API cập nhật theo thời gian thực hiển thị 2 điểm cuối để xử lý các yêu cầu đến để cập nhật kho hàng:

  • BỘ LƯU TRỮ – /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 thông số PARTNER_ID trên Trung tâm hành động được hiển thị dưới dạng Mã đối tác trên trang Tài khoản và người dùng, như được hiển thị trên ảnh chụp màn hình dưới đây.

Mã đối tác trên Cổng đối tác

Lấy 10000001 làm giá trị của PARTNER_ID làm ví dụ từ hàm ảnh chụp màn hình ở trên, các URL hoàn chỉnh để gửi yêu cầu API trong hộp cát và quá trình sản xuất sẽ như trong các ví dụ dưới đây.

# 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

Đang cập nhật thực thể

Để cập nhật các thực thể trong kho hàng của bạn, hãy sử dụng UPSERT UPSERT, và gửi các yêu cầu POST qua 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 thuộc bất kỳ loại thực thể nào có trong giản đồ kho hàng.

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

Nội dung yêu cầu là một đối tượng JSON có một danh sách các bản ghi. Mỗi bản ghi tương ứng với một thực thể đang được cập nhật. Mã này bao gồm trường data_record có tải trọng thực thể được mã hoá theo 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 của thực thể được giải mã phải có cùng cấu trúc như trong đặc tả 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 về thời điểm đã được tạo trong các hệ thống phụ trợ của bạn. 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 hàng. Nếu không bao gồm trường này, thời điểm mà Google nhận được yêu cầu sẽ được đặt thành thời điểm. Khi cập nhật một thực thể thông qua yêu cầu batchPush, thì trường generation_timestamp là được dùng để tạo phiên bản thực thể. Xem mong đợi định dạng của giá trị thời gian trong khoảng không quảng cáo quan hệ giản đồ.

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:

  • Nội dung tải trọng không được có kích thước vượt quá 5 MB. Tương tự như lô nguồn cấp dữ liệu, bạn nên bỏ khoảng trắng để có thể vừa 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 khẩn cấp số điện thoại của một nhà hàng. Thông tin bản cập nhật chứa JSON cho toàn bộ nhà hàng.

Hãy cân nhắc sử dụng nguồn cấp dữ liệu 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 bằng 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": "+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 2 thực thể nhà hàng trong một lệnh gọi API, hãy yêu cầu 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": "+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 trong thực đơn

Giả sử bạn cần thay đổi giá của một mục trong trình đơn.

Hãy cân nhắc sử dụng nguồn cấp dữ liệu 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 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 thông tin cập nhật theo thời gian thực để thêm thực thể mới vì điều này có thể dẫn đến những điểm không thống nhất của dữ liệu. Thay vào đó, hãy sử dụng nguồn cấp dữ liệu hàng loạt theo mô tả cho quy trình nhập hàng loạt.

Xoá đối tượng

Để xoá thực thể khỏi khoảng không quảng cáo của bạn, hãy sử dụng phím DELETE điểm cuối và gửi các yêu cầu POST qua HTTP. Mỗi yêu cầu POST phải bao gồm thông 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ỳ pháp nhân nào trong khoảng không quảng cáo của bạn.

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

Phần 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 các 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á. Tệp đối chiếu chỉ bao gồm từ loại thực thể và giá trị nhận dạng, ví dụ: bản trình bày JSON của 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 đã bị xoá trong hệ thống phụ trợ của bạn. Dấu thời gian này được dùng để xác định thứ tự áp dụng thao tác xoá đối với 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á 2 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ẽ là 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 lô. Bạn chỉ được xoá thực thể nhà hàng. Không xoá các thực thể phụ, chẳng hạn như các dịch vụ và trình đơn của Google, vì chúng sẽ tự động bị xoá.

Yêu cầu mẫu để xoá thực thể nhà hàng có mã nhận dạng 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"
    }
  ]
}
    

Xác thực và Mã phản hồi của API

Có hai loại xác thực được thực hiện đối với 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 tải trọng tuân thủ cập nhật hoặc xoá giản đồ và mỗi data_record đều chứa cả trường @id@type. Các bước kiểm tra này có tính đồng bộ và kết quả được trả về trong API nội dung phản hồi. Mã phản hồi 200 và phần nội dung JSON trống {} có nghĩa là các xác thực đã vượt qua và các thực thể trong yêu cầu đó đã được đưa vào hàng đợi đang xử lý. Mã phản hồi khác với 200 có nghĩa là một hoặc nhiều mã trong số này không xác thực được và toàn bộ yêu cầu đã bị từ chối (bao gồm tất cả thực thể trong tải trọng). Ví dụ: nếu data_record bị thiếu thuộc tính @type, thì phản hồi lỗi sau sẽ được trả về:

    {
      "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 dựa trên giản đồ quan hệ. Những vấn đề gặp phải ở giai đoạn xác thực này không được báo cáo trong API của bạn. Chúng chỉ được báo cáo trong Báo cáo RTU bảng điều khiển.

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 1.500 yêu cầu mỗi 60 giây hoặc 25 yêu cầu mỗi giây. Khi 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ử gọi lại vớ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 thực thể khác trong 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ố mẫu về cách sử dụng API cập nhật theo thời gian thực trong 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 tệp khoá tài khoản dịch vụ được tạo trong khoảng thời gian Thiết lập tài khoản. Đối với các giải pháp thay thế, hãy tham khảo 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 Generate Client Libraries (Tạo thư viện ứng dụng) để tạo mã nguồn cho các loại đối tượng khoảng không quảng cáo và đối tượng cập nhật theo thời gian thực.

Đang 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.

Mô hình mã nguồn ứng dụng trong các gói rtusamples.inventoryrtusamples.realtime được tạo bằng cách làm theo các bước trong 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.

Mô hình mã nguồn ứng dụng trong các gói rtusamples.inventoryrtusamples.realtime được tạo bằng cách làm theo các bước trong 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ề 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ì một lý do không mong muốn.

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

Nguồn cấp dữ liệu đầy đủ: Đảm bảo 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 kích hoạt lại.

Một số mặt hàng đã hết hàng MenuItemOffer Thông tin cập nhật theo thời gian thực: Gửi MenuItemOffer đóng gói với inventoryLevel được đặt thành 0 cho MenuItem và mọi dữ liệu khác đều không thay đổi.
Thay đổi giá món ăn trong thực đơn MenuItemOffer Thông tin cập nhật theo thời gian thực: Gửi MenuItemOffer đóng gói thực thể có price được đặt thành giá đã cập nhật cho MenuItem và mọi dữ liệu khác đều 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 thực đơn mới vào một 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à chờ nhập 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: Hãy gửi xoá rõ ràng.

Nguồn cấp dữ liệu đầy đủ: Đảm bảo 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 giao hàng mới trong một Service cụ thể ServiceArea Nguồn cấp dữ liệu theo lô: Gửi thực thể ServiceArea liên quan cùng với tất cả các trường còn nguyên vẹn, như cách bạn thường làm trong nguồn cấp dữ liệu đầy đủ, với khu vực giao hàng mới được chỉ định trong polygon, geoRadius hoặc postalCode.
Hãy cập nhật thời gian đến dự kiến (Service) ServiceHours Nguồn cấp dữ liệu theo lô: Gửi ServiceHours giống như trong các nguồn cấp dữ liệu, ngoại trừ leadTimeMin của nguồn cấp dữ liệu được cập nhật cho phù hợp.
Cập nhật giá giao hàng tại Service Fee Nguồn cấp dữ liệu theo lô: Gửi toàn bộ gói phân phối Fee kèm theo Đã cập nhật price.
Cập nhật giờ giao hàng hoặc mua mang đi trong Service ServiceHours Nguồn cấp dữ liệu theo lô: Gửi ServiceHours giống như trong các nguồn cấp dữ liệu, ngoại trừ các thuộc tính openscloses của nguồn cấp dữ liệu này đều được cập nhật cho phù hợp.
Service (thay đổi số tiền đặt hàng tối thiểu) Fee Nguồn cấp dữ liệu theo lô: Gửi Fee đầy đủ kèm theo minPrice đã cập nhật
Xoá vĩnh viễn một MenuItem 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 với parentMenuSectionId trống.

Thời gian xử lý các công việc theo lô và 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 hàng loạt sẽ được xử lý trong vòng 2 giờ trong khi thực thể được cập nhật thông qua cập nhật theo thời gian thực sẽ được xử lý 5 phút. Đáp thực thể cũ sẽ bị xoá sau 14 ngày nữa.

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

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