Aggiornamenti incrementali dell'inventario v1

Questa sezione descrive il modo in cui puoi inviare aggiornamenti urgenti dei tuoi feed a Google. L'API degli aggiornamenti incrementali consente di aggiornare ed eliminare entità nei feed in tempo quasi reale.

Questa funzionalità è principalmente pensata per gli aggiornamenti che non puoi prevedere, ad esempio le chiusure di emergenza. Di norma, qualsiasi modifica inviata tramite l'API degli aggiornamenti incrementali dovrebbe essere una modifica che deve essere pubblicata entro non più di una settimana. Se la modifica non deve essere subito visibile, puoi utilizzare un aggiornamento in batch. Gli aggiornamenti incrementali vengono elaborati in massimo cinque minuti.

Configurazione

Per implementare gli aggiornamenti incrementali:

  1. Per creare un progetto, segui i passaggi descritti in Creare e configurare un progetto.
  2. Segui i passaggi descritti in Configurare un account di servizio per creare un account di servizio. Tieni presente che devi essere un "Proprietario" del progetto per aggiungere un ruolo "Editor" per l'account di servizio
  3. (Facoltativo, ma consigliato) Installa la libreria client di Google nella lingua che preferisci per semplificare l'utilizzo di OAuth 2.0 quando chiami l'API. Le librerie di esempio incluse di seguito utilizzano queste librerie. In caso contrario, dovrai gestire manualmente gli scambi di token come descritto in Utilizzo di OAuth 2.0 per accedere alle API di Google.

Endpoint

Per informare Google di un aggiornamento, effettuare una richiesta HTTP POST all'API degli aggiornamenti incrementali e includere un payload di aggiornamenti e aggiunte. Lo schema dell'inventario che utilizzi determina quale endpoint effettuare la richiesta a:

Inventario v2

https://actions.googleapis.com/v2/apps/PROJECT_ID/entities/TYPE/ENTITY_ID:push

inventario v1

https://actions.googleapis.com/v2/apps/PROJECT_ID/entities/ENTITY_ID:push

Per rimuovere un'entità, effettua una richiesta HTTP DELETE al seguente endpoint che corrisponde allo schema di inventario utilizzato:

Inventario v2

https://actions.googleapis.com/v2/apps/PROJECT_ID/entities/TYPE/ENTITY_ID?entity.vertical=FOODORDERING&delete_time=DELETE_TIME

inventario v1

https://actions.googleapis.com/v2/apps/PROJECT_ID/entities/ENTITY_ID?entity.vertical=FOODORDERING&delete_time=DELETE_TIME

Nelle richieste riportate sopra, sostituisci quanto segue:

  • PROJECT_ID: ID progetto Google Cloud associato al progetto che hai creato nella sezione Creare e configurare un progetto.
  • TYPE (solo schema inventario v2): il tipo di entità (proprietà @type) dell'oggetto nel feed di dati che vuoi aggiornare.
  • ENTITY_ID: ID dell'entità inclusa nel payload. Assicurati di codificare l'ID dell'URL.
  • DELETE_TIME (solo eliminazione endpoint): campo facoltativo per indicare l'ora in cui l'entità è stata eliminata sui sistemi (per impostazione predefinita viene ricevuta la richiesta). Il valore dell'ora non deve essere futuro. Quando si invia un'entità tramite una chiamata incrementale, il controllo delle versioni delle entità utilizza anche il campo delete_time in caso di chiamata di eliminazione. Formatta questo valore come yyyy-mm-ddTHH:mm:ssZ

Ad esempio, hai un progetto con ID "delivery-provider-id&quot"; che utilizza lo schema di inventario v2. Vuoi apportare modifiche al ristorante con un tipo di entità ristorante "MenuSection" e un ID entità "menuSection_122". L'endpoint per gli aggiornamenti dei dati sarebbe il seguente:

https://actions.googleapis.com/v2/apps/delivery-provider-id/entities/MenuSection/menuSection_122:push

Per rimuovere questa stessa entità, devi effettuare questa chiamata API HTTP DELETE:

https://actions.googleapis.com/v2/apps/delivery-provider-id/entities/MenuSection/menuSection_122?entity.vertical=FOODORDERING

Richieste sandbox

Per le richieste sandbox, segui le istruzioni riportate nella sezione Endpoint in alto, ma fai richieste a /v2/sandbox/apps/ anziché a /v2/apps/. Ad esempio, una richiesta di eliminazione sandbox per lo schema dell'inventario v2 è strutturata nel seguente modo:

https://actions.googleapis.com/v2/sandbox/apps/PROJECT_ID/entities/TYPE/ENTITY_ID?entity.vertical=FOODORDERING&delete_time=DELETE_TIME

Aggiornamenti e aggiunte

I tuoi feed batch giornalieri devono contenere anche eventuali modifiche inviate tramite questa API. In caso contrario, gli aggiornamenti collettivi sovrascriveranno le modifiche incrementali.

Payload

Ogni richiesta POST deve includere i parametri della richiesta insieme al payload JSON contenente i dati strutturati di qualsiasi tipo di entità elencato nello schema dell'inventario.

Il file JSON dovrebbe avere lo stesso aspetto del feed batch, con le seguenti differenze:

  • Il corpo del payload non deve superare i 5 MB. Analogamente ai feed batch, ti suggeriamo di eliminare gli spazi vuoti per interessare più dati.
  • La busta è la seguente:
{
  "entity": {
    "data":"ENTITY_DATA",
    "vertical":"FOODORDERING"
  },
  "update_time":"UPDATE_TIMESTAMP"
}

Nel payload indicato sopra, sostituisci quanto segue:

  • ENTITY_DATA: entità in formato JSON serializzata come stringa. L'entità JSON-LD deve essere passato come stringa nel campo data.
  • (Facoltativo) UPDATE_TIMESTAMP: timestamp quando è stata aggiornata l'entità nei sistemi. Il valore dell'ora non deve essere futuro. Il timestamp predefinito è il momento in cui Google riceve la richiesta. Quando si invia un'entità tramite una richiesta incrementale, il controllo delle versioni delle entità utilizza anche il campo update_time nel caso di una richiesta di aggiunta/aggiornamento.

Aggiornamento di un'entità

Esempio 1: aggiornamento di un ristorante

Supponiamo che tu debba aggiornare urgentemente il numero di telefono di un ristorante, L'aggiornamento contiene JSON per l'intero ristorante.

Considera un feed batch simile al seguente:

{
  "@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
}

L'aggiornamento incrementale tramite POST HTTP sarebbe il seguente:

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"
  }
}

Esempio 2: aggiornamento del prezzo di una voce di menu

Supponi di dover modificare il prezzo di una voce del menu. Come nell'esempio 1, l'aggiornamento deve contenere il JSON per l'intera entità di primo livello (il menu) e il feed utilizza lo schema dell'inventario v1.

Considera un feed batch simile al seguente:

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

L'aggiornamento incrementale tramite POST sarebbe il seguente:

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"
  }
}

Aggiungere un'entità

Per aggiungere entità, evita di utilizzare gli aggiornamenti dell'inventario. Utilizza invece la procedura dei feed batch come descritto per lo schema di inventario v2.

Rimozione di un'entità

Per rimuovere le entità di primo livello, devi utilizzare un endpoint leggermente modificato e utilizzare HTTP DELETE anziché HTTP POST nella richiesta.

Non utilizzare HTTP DELETE per rimuovere un'entità secondaria all'interno di un'entità di primo livello, ad esempio una voce di menu all'interno di un menu. Considera invece la rimozione delle entità secondarie come un aggiornamento a un'entità di primo livello in cui la entità secondaria viene rimossa dall'elenco o dal parametro pertinente.

Esempio 1: eliminazione di un'entità di primo livello

Prendi in considerazione una situazione in cui vuoi eliminare un ristorante in un feed che utilizza lo schema dell'inventario v1. Devi anche eliminare i relativi servizi e menu.

Un endpoint di esempio per un'entità di menu con ID "https://www.provider.com/ristorante/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

Un endpoint di esempio per un'entità ristorante con ID https://www.provider.com/ristorante/nr":

DELETE v2/apps/delivery-provider-id/entities/https%3A%2F%2Fwww.provider.com%2Frestaurant%2Fnr?entity.vertical=FOODORDERING
Host: actions.googleapis.com

Un endpoint di esempio per un'entità di servizio con ID https://www.provider.com/ristorante/servizio/nr":

DELETE v2/apps/delivery-provider-id/entities/https%3A%2F%2Fwww.provider.com%2Frestaurant%2Fservice%2Fnr?entity.vertical=FOODORDERING
Host: actions.googleapis.com
}

Esempio 2: rimozione delle entità secondarie

Per rimuovere una entità secondaria da un'entità di primo livello, devi inviare l'entità di primo livello con l'entità secondaria rimossa dal campo corrispondente. Il seguente esempio presuppone che il feed utilizzi lo schema dell'inventario v1.

Ad esempio, per rimuovere un'area coperta dal servizio, aggiorna l'area coperta dal servizio nell'elenco areaServed.

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"
  }
}

Codici di risposta API

Una chiamata riuscita non significa che il feed è valido o corretto, ma solo che la chiamata API è stata effettuata. Le chiamate riuscite ricevono un codice di risposta HTTP 200, insieme a un corpo di risposta vuoto:

{}

In caso di errori, il codice di risposta HTTP non è 200 e il corpo della risposta indica l'errore.

Ad esempio, se l'utente ha impostato il valore "vertical" sulla busta su FAKE_VERTICAL, riceverai il seguente messaggio:

{
  "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\""
          }
        ]
      }
    ]
  }
}

Esempio di codice

Di seguito sono riportati alcuni esempi di come utilizzare l'API Incremental Updates in varie lingue. Questi esempi utilizzano le librerie di autenticazione Google e presuppongono un feed utilizzando lo schema dell'inventario v1. Per soluzioni alternative, consulta Utilizzo di OAuth 2.0 per le applicazioni server-server.

Aggiornamento delle entità

Node.js

Questo codice utilizza la libreria di autenticazione Google per 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

Questo codice utilizza la libreria di autenticazione Google per Python.

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

Questo codice utilizza la libreria di autenticazione Google per Java.

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);
}

Rimozione delle entità

Node.js

Questo codice utilizza la libreria di autenticazione Google per 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

Questo codice utilizza la libreria di autenticazione Google per Python.

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

Questo codice utilizza la libreria di autenticazione Google per Java.

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));
}

Casi d'uso

Di seguito sono riportati alcuni esempi di aggiornamenti incrementali, aggiornamenti completi dei feed e contenuti nella chiamata API in generale:

Scenario Entità di primo livello Descrizione ed effetti
Disabilitazione di un servizio DisabledService

Devi disattivare un servizio per un motivo imprevisto.

Aggiornamenti incrementali: invia l'entità Service in questione con @type modificata in DisabledService, mantenendo inalterate le altre proprietà.

Feed completi: assicurati di aggiornare l'entità dal feed completo impostando @type su DisabledService prima del recupero successivo da parte di Google, altrimenti l'entità verrà riattivata.

Un articolo specifico non è disponibile Menu Aggiornamenti incrementali: invia l'entità Menu incapsulante con offer.inventoryLevel impostato su 0 per la data MenuItem e tutti gli altri dati invariati.
Variazione di prezzo della voce di menu Menu Aggiornamenti incrementali: invia l'entità Menu incapsulante con offer.price impostato sul prezzo aggiornato per l'elemento MenuItem e tutti gli altri dati invariati.

Aggiungi nuova entità di primo livello

Applicabile solo all'entità di tipo Menu, Restaurant e Service.

Menu, Restaurant e Service

Ad esempio, devi aggiungere un nuovo menu a un ristorante.

Aggiornamenti incrementali: invia la nuova entità del menu e l'entità del ristorante con il relativo campo hasMenu.

Elimina l'entità di primo livello in modo permanente

Applicabile solo all'entità di tipo Menu, Restaurant e Service.

Menu, Restaurant e Service

Aggiornamenti incrementali: invia un'eliminazione esplicita.

Feed completi: assicurati di rimuovere l'entità dai feed completi prima del successivo recupero da parte di Google, altrimenti l'entità verrà riaggiunta.

Aggiungi una nuova area di consegna in un determinato Service Service Feed incrementali: invia l'entità Service in questione con tutti i campi inalterati, come faresti normalmente all'interno dei feed completi, con una nuova area di consegna specificata entro areaServed dal campo Service.
Aggiorna l'ora di arrivo stimata per la consegna in Service Service Feed incrementali: invia il valore Service allo stesso modo dei feed, tranne per il fatto che il file hoursAvailable.deliveryHours viene aggiornato di conseguenza.
Aggiorna i prezzi di consegna in Service Service Feed incrementali: invia un Service completo con offers.priceSpecification.price aggiornato.
Aggiorna l'orario di consegna o ritiro in Service Service Feed incrementali: invia il valore Service allo stesso modo dei feed, tranne per il fatto che il file hoursAvailable viene aggiornato di conseguenza.
Service (importo minimo della modifica dell'ordine) Service Feed incrementali: invia un Service completo con Service.offers.priceSpecification.eligibleTransactionVolume aggiornato
Elimina MenuItem in modo permanente Menu Feed incrementali: invia Menu come nei feed, ma con questo elemento MenuItem rimosso dall'elenco hasMenuItems.

SLO sul tempo di elaborazione per i job batch e gli aggiornamenti incrementali

Un'entità aggiunta tramite un aggiornamento batch o incrementale verrà elaborata in uno o due giorni. Un'entità aggiornata o eliminata tramite un batch verrà elaborata in 2 ore, mentre un'entità aggiornata tramite un aggiornamento incrementale verrà elaborata in 5 minuti. Un'entità inattiva viene eliminata entro 7 giorni.

Puoi inviare a Google:

  • Più job batch al giorno per mantenere aggiornato l'inventario. OPPURE
  • Un job batch al giorno e API incrementali per mantenere aggiornato l'inventario.