Z tej sekcji dowiesz się, jak wysyłać do Google aktualizacje plików danych, które mają charakter pilny. Interfejs API Incremental Updates umożliwia aktualizowanie i usuwanie elementów w plikach danych w czasie zbliżonym do rzeczywistego.
Ta funkcja jest przeznaczona głównie do aktualizacji, których nie można przewidzieć, takich jak zamknięcia awaryjne. Zwykle każda zmiana przesłana za pomocą interfejsu API Incremental Updates API powinna zostać wprowadzona w ciągu maksymalnie 1 tygodnia. Jeśli zmiana nie musi być odzwierciedlona natychmiast, możesz użyć aktualizacji zbiorczej. Aktualizacje przyrostowe są przetwarzane w ciągu nie dłużej niż 5 minut.
Konfiguracja
Aby wdrożyć aktualizacje przyrostowe, wykonaj te czynności:
- Aby utworzyć projekt, wykonaj czynności opisane w artykule Tworzenie i konfigurowanie projektu.
- Aby utworzyć konto usługi, wykonaj czynności opisane w artykule Konfigurowanie konta usługi. Pamiętaj, że musisz być „Właścicielem” projektu, aby dodać rolę „Edytujący” dla konta usługi.
- (Opcjonalnie, ale zalecane) Zainstaluj bibliotekę klienta Google w wybranym języku, aby ułatwić korzystanie z OAuth 2.0 podczas wywoływania interfejsu API. Poniżej znajdziesz przykłady kodu, które korzystają z tych bibliotek. W przeciwnym razie musisz ręcznie przeprowadzić wymianę tokenów zgodnie z opisem w artykule Uzyskiwanie dostępu do interfejsów API Google za pomocą protokołu OAuth 2.0.
Punkt końcowy
Aby powiadomić Google o aktualizacji, wyślij żądanie HTTP POST do interfejsu IncrementalUpdates API, dołączając ładunek aktualizacji i dodatków. Używany przez Ciebie schemat zasobów reklamowych określa, do którego punktu końcowego należy wysłać żądanie:
zasoby reklamowe w wersji 2
https://actions.googleapis.com/v2/apps/PROJECT_ID/entities/TYPE/ENTITY_ID:push
zasoby reklamowe w wersji 1
https://actions.googleapis.com/v2/apps/PROJECT_ID/entities/ENTITY_ID:push
Aby usunąć element, wyślij żądanie HTTP DELETE do punktu końcowego odpowiadającego schematowi asortymentu, którego używasz:
zasoby reklamowe w wersji 2
https://actions.googleapis.com/v2/apps/PROJECT_ID/entities/TYPE/ENTITY_ID?entity.vertical=FOODORDERING&delete_time=DELETE_TIME
zasoby reklamowe w wersji 1
https://actions.googleapis.com/v2/apps/PROJECT_ID/entities/ENTITY_ID?entity.vertical=FOODORDERING&delete_time=DELETE_TIME
W powyższych prośbach zastąp:
- PROJECT_ID: identyfikator projektu Google Cloud powiązany z projektem utworzonym w sekcji Tworzenie i konfigurowanie projektu.
- TYPE (dotyczy tylko schematu asortymentu w wersji 2): typ elementu (właściwość
@type
) w pliku danych, który chcesz zaktualizować. - ENTITY_ID: identyfikator zasobu zawartego w ładunku. Zakoduj identyfikator za pomocą kodowania URL.
- DELETE_TIME (tylko punkt końcowy usuwania): opcjonalne pole do oznaczania czasu, w którym element został usunięty z Twoich systemów (domyślnie jest to czas otrzymania żądania). Wartość czasu nie może być w przyszłości. Podczas wysyłania elementu za pomocą wywołania cząstkowego wersja elementu używa również pola
delete_time
w przypadku wywołania usuwania. Sformatuj tę wartość jakoyyyy-mm-ddTHH:mm:ssZ
Na przykład masz projekt o identyfikatorze „delivery-provider-id”, który używa schematu zapasów v2. Chcesz wprowadzić zmiany w restauracji o typie „MenuSection” i identyfikatorze „menuSection_122”. Punkt końcowy do aktualizacji danych:
https://actions.googleapis.com/v2/apps/delivery-provider-id/entities/MenuSection/menuSection_122:push
Aby usunąć ten sam element, wykonaj to wywołanie interfejsu API HTTP DELETE:
https://actions.googleapis.com/v2/apps/delivery-provider-id/entities/MenuSection/menuSection_122?entity.vertical=FOODORDERING
Prośby o piaskownicę
W przypadku próśb o dostęp do piaskownicy postępuj zgodnie ze wskazówkami podanymi powyżej w sekcji Punkt końcowy, ale zamiast do punktu /v2/apps/
wysyłaj żądania do punktu /v2/sandbox/apps/
. Na przykład prośba o usunięcie sandboxa w przypadku schematu zapasów wersji 2 jest sformułowana w ten sposób:
https://actions.googleapis.com/v2/sandbox/apps/PROJECT_ID/entities/TYPE/ENTITY_ID?entity.vertical=FOODORDERING&delete_time=DELETE_TIME
Aktualizacje i uzupełnienia
Twoje codzienne pliki zbiorcze powinny też zawierać wszelkie zmiany przesłane za pomocą tego interfejsu API. W przeciwnym razie aktualizacje zbiorcze zastąpią Twoje zmiany przyrostowe.
Ładunek
Każde żądanie POST musi zawierać parametry żądania wraz z ładunkiem JSON zawierającym uporządkowane dane dowolnego typu elementu wymienionego w schemacie zasobów reklamowych.
Plik JSON powinien wyglądać tak samo jak plik danych zbiorczych, z tymi różnicami:
- Rozmiar ładunku nie powinien przekraczać 5 MB. Podobnie jak w przypadku plików danych zbiorczych, zalecamy usunięcie spacji, aby zmieścić więcej danych.
- Korespondencja ma postać:
{ "entity": { "data":"ENTITY_DATA", "vertical":"FOODORDERING" }, "update_time":"UPDATE_TIMESTAMP" }
W powyższym pliku danych zastąp:
- ENTITY_DATA: element w formacie JSON serializowany jako ciąg znaków. Encję JSON-LD należy przekazać jako ciąg znaków w polu
data
. - UPDATE_TIMESTAMP (opcjonalnie): sygnatura czasowa, kiedy element został zaktualizowany w Twoich systemach. Wartość czasu nie może być w przyszłości. Domyślna sygnatura czasowa to moment, w którym Google otrzymało żądanie. Podczas wysyłania elementu za pomocą żądania przyrostowego wersja elementu korzysta z pola
update_time
w przypadku żądania dodania lub zaktualizowania.
Aktualizowanie elementu
Przykład 1. Aktualizowanie restauracji
Załóżmy, że musisz pilnie zaktualizować numer telefonu restauracji. Aktualizacja zawiera plik JSON całej restauracji.
Weź pod uwagę plik danych zbiorczego, który wygląda tak:
{ "@type": "Restaurant", "@id": "restaurant12345", "name": "Some Restaurant", "url": "https://www.provider.com/somerestaurant", "telephone": "+16501234567", "streetAddress": "345 Spear St", "addressLocality": "San Francisco", "addressRegion": "CA", "postalCode": "94105", "addressCountry": "US", "latitude": 37.472842, "longitude": -122.217144 }
Wtedy przyrostowa aktualizacja za pomocą HTTP POST będzie wyglądać tak:
POST v2/apps/provider-project/entities/Restaurant/restaurant12345:push Host: actions.googleapis.com Content-Type: application/ld+json { "entity": { "data": { "@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 }, "vertical": "FOODORDERING" } }
Przykład 2. Zmiana ceny pozycji menu
Załóżmy, że musisz zmienić cenę pozycji menu. Podobnie jak w przykładzie 1, Twoja aktualizacja musi zawierać dane JSON dotyczące całego elementu najwyższego poziomu (menu), a plik danych musi używać schematu zasobów reklamowych w wersji 1.
Weź pod uwagę plik danych zbiorczego, który wygląda tak:
{ "@type": "MenuItemOffer", "@id": "menuitemoffer6680262", "sku": "offer-cola", "menuItemId": "menuitem896532", "price": 3.00, "priceCurrency": "USD" }
Wtedy przyrostowa aktualizacja za pomocą żądania POST będzie wyglądać tak:
POST v2/apps/provider-project/entities/MenuItemOffer/menuitemoffer6680262:push Host: actions.googleapis.com Content-Type: application/ld+json { "entity": { "data": { "@type": "MenuItemOffer", "@id": "menuitemoffer6680262", "sku": "offer-cola", "menuItemId": "menuitem896532", "price": 1.00, "priceCurrency": "USD" }, "vertical": "FOODORDERING" } }
Dodawanie elementu
Aby dodawać elementy, nie używaj aktualizacji asortymentu. Zamiast tego użyj procesu przesyłania plików zbiorczych zgodnie z opisem w sekcji Schemat asortymentu w wersji 2.
Usuwanie elementu
Aby usunąć elementy najwyższego poziomu, użyj nieco zmodyfikowanego punktu końcowego i w żądaniu użyj metody HTTP DELETE zamiast HTTP POST.
Nie używaj metody HTTP DELETE do usuwania podelementu w elemencie najwyższego poziomu, np. pozycji menu w menu. Zamiast tego usuwanie podrzędnych jednostek traktuj jako aktualizację jednostki najwyższego poziomu, w której podrzędna jednostka jest usuwana z odpowiedniej listy lub parametru.
Przykład 1. Usuwanie elementu najwyższego poziomu
Wyobraź sobie sytuację, w której chcesz usunąć restaurację z pliku danych, który używa schematu asortymentu w wersji 1. Musisz też usunąć usługi i menu.
Przykładowy punkt końcowy dla elementu menu o identyfikatorze „https://www.provider.com/restaurant/menu/nr”:
DELETE v2/apps/delivery-provider-id/entities/https%3A%2F%2Fwww.provider.com%2Frestaurant%2Fmenu%2Fnr?entity.vertical=FOODORDERING
Host: actions.googleapis.com
Przykładowy punkt końcowy dla obiektu restauracji o identyfikatorze „https://www.provider.com/restaurant/nr”:
DELETE v2/apps/delivery-provider-id/entities/https%3A%2F%2Fwww.provider.com%2Frestaurant%2Fnr?entity.vertical=FOODORDERING
Host: actions.googleapis.com
Przykład punktu końcowego dla elementu usługi o identyfikatorze „https://www.provider.com/restaurant/service/nr”:
DELETE v2/apps/delivery-provider-id/entities/https%3A%2F%2Fwww.provider.com%2Frestaurant%2Fservice%2Fnr?entity.vertical=FOODORDERING
Host: actions.googleapis.com
}
Przykład 2. Usuwanie podelementów
Aby usunąć element podrzędny z elementu najwyższego poziomu, wyślij element najwyższego poziomu z elementem podrzędnym usuniętym z odpowiedniego pola. W tym przykładzie zakładamy, że plik danych korzysta ze schematu asortymentu w wersji 1.
Aby na przykład usunąć obszar działalności, zaktualizuj usługę, usuwając z listy areaServed
obsługiwany obszar.
POST v2/apps/delivery-provider-id/entities/https%3A%2F%2Fwww.provider.com%2Frestaurant%2Fservice%2Fnr:push
Host: actions.googleapis.com
Content-Type: application/ld+json
{
"entity": {
// Note: "data" is not serialized as a string in our example for readability.
"data": {
"@type": "Service",
"provider": {
"@type": "Restaurant",
"@id": "https://www.provider.com/restaurant/nr"
},
"areaServed": [
{
"@type": "GeoCircle",
"geoMidpoint": {
"@type": "GeoCoordinates",
"latitude": "42.362757",
"longitude": "-71.087109"
},
"geoRadius": "10000"
}
// area2 is removed.
]
...
},
"vertical": "FOODORDERING"
}
}
Kody odpowiedzi interfejsu API
Pomyślne wywołanie nie oznacza, że plik danych jest prawidłowy lub poprawny, tylko że zostało wykonane wywołanie interfejsu API. Pomyślne wywołania otrzymują kod odpowiedzi HTTP 200 oraz pustą treść odpowiedzi:
{}
W przypadku niepowodzenia kod odpowiedzi HTTP nie będzie miał wartości 200, a ciało odpowiedzi będzie wskazywać, co poszło nie tak.
Jeśli np. użytkownik ustawi wartość „vertical” w kopercie na
FAKE_VERTICAL
, otrzymasz tę wiadomość:
{
"error": {
"code": 400,
"message": "Invalid value at 'entity.vertical' (TYPE_ENUM), \"FAKE_VERTICAL\"",
"status": "INVALID_ARGUMENT",
"details": [
{
"@type": "type.googleapis.com/google.rpc.BadRequest",
"fieldViolations": [
{
"field": "entity.vertical",
"description": "Invalid value at 'entity.vertical' (TYPE_ENUM), \"FAKE_VERTICAL\""
}
]
}
]
}
}
Przykładowy kod
Poniżej znajdziesz kilka przykładów użycia interfejsu Incremental Updates API w różnych językach. Te przykłady korzystają z bibliotek Google Auth Library i zakładają, że plik danych używa schematu asortymentu w wersji 1. Alternatywnych rozwiązań szukaj w artykule Używanie protokołu OAuth 2.0 w aplikacjach międzyserwerowych.
Aktualizuję elementy
Node.js
Ten kod używa biblioteki Google do uwierzytelniania w Node.js.
const {auth} = require('google-auth-library') const request = require('request'); // The service account client secret file downloaded from the Google Cloud Console const serviceAccountJson = require('./service-account.json') // entity.json is a file that contains the entity data in json format const entity = require('./entity.json') const ENTITY_ID = 'restaurant/http://www.provider.com/somerestaurant' const PROJECT_ID = 'your-project-id' /** * Get the authorization token using a service account. */ async function getAuthToken() { let client = auth.fromJSON(serviceAccountJson) client.scopes = ['https://www.googleapis.com/auth/assistant'] const tokens = await client.authorize() return tokens.access_token; } /** * Send an incremental update to update or add an entity */ async function updateEntity(entityId, entity) { const token = await getAuthToken() request.post({ headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, url: `https://actions.googleapis.com/v2/apps/${PROJECT_ID}/entities/${encodeURIComponent(entityId)}:push`, body: { entity: { data: JSON.stringify(entity), vertical: 'FOODORDERING', } }, json: true }, (err, res, body) => { if (err) { return console.log(err); } console.log(`Response: ${JSON.stringify(res)}`) }) } updateEntity(ENTITY_ID, entity)
Python
Ten kod korzysta z biblioteki uwierzytelniania Google dla Pythona.
from google.oauth2 import service_account from google.auth.transport.requests import AuthorizedSession import json import urllib PROJECT_ID = 'your-project-id' ENTITY_ID = 'restaurant/http://www.provider.com/somerestaurant' ENDPOINT = 'https://actions.googleapis.com/v2/apps/%s/entities/%s:push' % ( PROJECT_ID, urllib.quote(ENTITY_ID, '')) # service-account.json is the service account client secret file downloaded from the # Google Cloud Console credentials = service_account.Credentials.from_service_account_file( 'service-account.json') scoped_credentials = credentials.with_scopes( ['https://www.googleapis.com/auth/assistant']) authed_session = AuthorizedSession(scoped_credentials) # Retrieving the entity update_file = open("entity.json") #JSON file containing entity data in json format. data = update_file.read() # Populating the entity with wrapper entity = {} entity['data'] = data #entity JSON-LD serialized as string entity['vertical'] = 'FOODORDERING' request = {} request['entity'] = entity response = authed_session.post(ENDPOINT, json=request) print(response.text) #if successful, will be '{}'
Java
Ten kod korzysta z biblioteki Google do uwierzytelniania w Javie.
private static final String PROJECT_ID = "your-project-id"; private static final String ENTITY_ID = "http://www.provider.com/somerestaurant"; /** * Get the authorization token using a service account. */ private static String getAuthToken() { InputStream serviceAccountFile = Example.class.getClassLoader().getResourceAsStream("service-account.json"); ServiceAccountCredentials.Builder credentialsSimpleBuilder = ServiceAccountCredentials.fromStream(serviceAccountFile).toBuilder(); credentialsSimpleBuilder.setScopes(ImmutableList.of("https://www.googleapis.com/auth/assistant")); AccessToken accessToken = credentialsSimpleBuilder.build().refreshAccessToken(); return accessToken.getTokenValue(); } /** * Send an incremental update to update or add an entity. * @param entityId The id of the entity to update. * @param entity the json of the entity to be updated. */ public void updateEntity(String entityId, JSONObject entity) { String authToken = getAuthToken(); String endpoint = String.format( "https://actions.googleapis.com/v2/apps/%s/entities/%s:push", PROJECT_ID, URLEncoder.encode(entityId, "UTF-8")); JSONObject data = new JSONObject(); data.put("data", entity.toString()); data.put("vertical", "FOODORDERING"); JSONObject jsonBody = new JSONObject(); jsonBody.put("entity", data); // Execute POST request executePostRequest(endpoint, authToken, jsonBody); }
Usuwanie elementów
Node.js
Ten kod używa biblioteki Google do uwierzytelniania w Node.js.
const {auth} = require('google-auth-library') const request = require('request'); // The service account client secret file downloaded from the Google Cloud Console const serviceAccountJson = require('./service-account.json') // entity.json is a file that contains the entity data in json format const entity = require('./entity.json') const ENTITY_ID = 'restaurant/http://www.provider.com/somerestaurant' const PROJECT_ID = 'your-project-id' /** * Get the authorization token using a service account. */ async function getAuthToken() { let client = auth.fromJSON(serviceAccountJson) client.scopes = ['https://www.googleapis.com/auth/assistant'] const tokens = await client.authorize() return tokens.access_token; } /** * Send an incremental update to delete an entity */ async function deleteEntity(entityId) { const token = await getAuthToken() request.delete({ headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, url: `https://actions.googleapis.com/v2/apps/${PROJECT_ID}/entities/${encodeURIComponent(entityId)}?entity.vertical=FOODORDERING`, body: {}, json: true }, (err, res, body) => { if (err) { return console.log(err); } console.log(`Response: ${JSON.stringify(res)}`) }) } deleteEntity(ENTITY_ID)
Python
Ten kod korzysta z biblioteki uwierzytelniania Google dla Pythona.
from google.oauth2 import service_account from google.auth.transport.requests import AuthorizedSession import json import urllib # Service config PROJECT_ID = 'your-project-id' ENTITY_ID = 'restaurant/http://www.provider.com/somerestaurant' DELETE_TIME = '2018-04-07T14:30:00-07:00' ENDPOINT = 'https://actions.googleapis.com/v2/apps/%s/entities/%s?entity.vertical=FOODORDERING&delete_time=%s' % ( PROJECT_ID, urllib.quote(ENTITY_ID, ''), urllib.quote(DELETE_TIME, '')) # service-account.json is the service account client secret file downloaded from the # Google Cloud Console credentials = service_account.Credentials.from_service_account_file( 'service-account.json') scoped_credentials = credentials.with_scopes( ['https://www.googleapis.com/auth/assistant']) authed_session = AuthorizedSession(scoped_credentials) response = authed_session.delete(ENDPOINT) print(response.text) #if successful, will be '{}'
Java
Ten kod korzysta z biblioteki Google do uwierzytelniania w Javie.
private static final String PROJECT_ID = "your-project-id"; private static final String ENTITY_ID = "restaurant/http://www.provider.com/somerestaurant"; /** * Get the authorization token using a service account. */ private static String getAuthToken() { InputStream serviceAccountFile = Example.class.getClassLoader().getResourceAsStream("service-account.json"); ServiceAccountCredentials.Builder credentialsSimpleBuilder = ServiceAccountCredentials.fromStream(serviceAccountFile).toBuilder(); credentialsSimpleBuilder.setScopes(ImmutableList.of("https://www.googleapis.com/auth/assistant")); AccessToken accessToken = credentialsSimpleBuilder.build().refreshAccessToken(); return accessToken.getTokenValue(); } /** * Send an incremental update to delete an entity. * @param entityId The id of the entity to delete. */ public void deleteEntity(String entityId) { String authToken = getAuthToken(); String endpoint = String.format( "https://actions.googleapis.com/v2/apps/%s/entities/%s?entity.vertical=FOODORDERING", PROJECT_ID, URLEncoder.encode(entityId, "UTF-8")); // Execute DELETE request System.out.println(executeDeleteRequest(endpoint, authToken)); }
Przypadki użycia
Poniższe przypadki użycia to przykłady przyrostowych aktualizacji, pełnych aktualizacji pliku danych oraz treści na wysokim poziomie w wywołaniu interfejsu API:
Scenariusz | Element najwyższego poziomu | Opis i efekty |
---|---|---|
Wyłączanie usługi | DisabledService |
musisz wyłączyć usługę z nieprzewidzianego powodu; Aktualizacje przyrostowe: prześlij element Pełne pliki danych: przed następnym pobraniem przez Google pamiętaj, aby zaktualizować element z pełnych plików danych, aby wartość |
konkretny produkt jest niedostępny, | Menu |
Aktualizacje przyrostowe: wyślij element Menu , w którym element offer.inventoryLevel ma wartość 0 dla danego MenuItem , a wszystkie inne dane pozostają bez zmian. |
Zmiana ceny pozycji menu | Menu |
Aktualizacje przyrostowe: prześlij element Menu zawierający offer.price zaktualizowaną ceną dla danego MenuItem , a wszystkie inne dane bez zmian. |
Dodawanie nowej jednostki najwyższego poziomu Dotyczy tylko elementów typu |
Menu , Restaurant , Service |
Możesz na przykład dodać nowe menu do restauracji. Aktualizacje przyrostowe: wyślij nowy typ menu wraz z typem restauracji, a pole |
Trwałe usuwanie elementu najwyższego poziomu Dotyczy tylko elementów typu |
Menu , Restaurant , Service |
Aktualizacje przyrostowe: wyślij wyraźne usunięcie. Pełne pliki danych: przed kolejnym pobraniem przez Google pamiętaj, aby usunąć element z pełnych plików danych. W przeciwnym razie zostanie on ponownie dodany. |
Dodawanie nowej strefy dostawy w określonym Service |
Service |
Pliki danych przyrostowe: prześlij odpowiednią jednostkę Service ze wszystkimi polami, tak jak w pełnych plikach danych, z nową strefą docelową określoną w areaServed Service . |
Zaktualizuj szacowany czas dostawy w Service |
Service |
Dodatkowe pliki danych: wyślij Service w taki sam sposób jak w plikach danych, z tą różnicą, że hoursAvailable.deliveryHours zostanie odpowiednio zaktualizowany. |
Zaktualizuj ceny dostawy w Service |
Service |
Pliki danych przyrostowe: prześlij pełny plik Service z aktualizowanymi informacjami offers.priceSpecification.price . |
Zmień godziny dostawy lub odbioru na wynos w Service |
Service |
Dodatkowe pliki danych: wyślij Service w taki sam sposób jak w plikach danych, z tą różnicą, że hoursAvailable zostanie odpowiednio zaktualizowany. |
Service (zmiana minimalnej wartości zamówienia) |
Service |
Pliki danych przyrostowe: prześlij pełny plik danych Service z aktualizacją Service.offers.priceSpecification.eligibleTransactionVolume |
Usuń MenuItem na stałe |
Menu |
Dodatkowe pliki danych: wyślij Menu taki sam jak w plikach danych, ale bez tego MenuItem , który został usunięty z listy hasMenuItems . |
Docelowy poziom usług dotyczący czasu przetwarzania zadań zbiorczych i aktualizacji przyrostowych
Element dodany za pomocą zbiorczego lub przyrostowego procesu aktualizacji zostanie przetworzony w ciągu 1–2 dni. Element zaktualizowany lub usunięty w ramach zbiorczego przetwarzania zostanie przetworzony w ciągu 2 godzin, a element zaktualizowany w ramach stopniowego przetwarzania – w ciągu 5 minut. Nieaktualne elementy są usuwane po 7 dniach.
Możesz wysłać do Google:
- wiele zadań zbiorczych dziennie, aby aktualizować asortyment, lub
- Jedno zadanie zbiorcze dziennie i interfejsy API w celu aktualizowania asortymentu.