이 섹션에서는 시간에 민감한 피드 업데이트를 Google 증분 업데이트 API를 사용하면 피드합니다.
이 기능은 예측 불가능한 업데이트에 주로 사용되므로 긴급 폐쇄와 같은 조치를 취할 수 있습니다 일반적으로 Ad Manager를 통해 제출된 모든 변경사항은 증분 업데이트 API는 다음 시간 내에 게시되어야 하는 변경사항이어야 합니다. 1주일 변경사항을 즉시 반영할 필요가 없는 경우 대신 일괄 업데이트를 사용하세요 증분 업데이트는 5회 이내에 처리됩니다. 합니다.
설정
증분 업데이트를 구현하려면 다음 단계를 따르세요.
- 프로젝트 만들기 및 설정하기에 설명된 단계를 따라 다음 작업을 수행합니다. 프로젝트를 만듭니다
- 서비스 계정 설정하기에 설명된 단계를 따릅니다. 서비스 계정을 만듭니다 '소유자'여야 합니다. 의 'Editor'를 추가하여 서비스 계정의 역할
- (선택사항이나 권장됨) Google 클라이언트 라이브러리를 설치합니다. 호출 시 OAuth 2.0을 쉽게 사용할 수 있도록 API에 액세스할 수 있습니다. 아래에 포함된 코드 샘플은 이러한 라이브러리를 사용합니다. 그렇지 않으면 OAuth 2.0을 사용하여 Google API에 액세스하기에 설명된 대로 토큰 교환을 수동으로 처리해야 합니다.
엔드포인트
Google에 업데이트를 알리려면 증분 업데이트 API와 업데이트 및 추가사항의 페이로드를 포함합니다. 사용하는 인벤토리 스키마에 따라 요청을 수행할 엔드포인트가 결정됩니다.
v2 인벤토리
https://actions.googleapis.com/v2/apps/PROJECT_ID/entities/TYPE/ENTITY_ID:push
v1 인벤토리
https://actions.googleapis.com/v2/apps/PROJECT_ID/entities/ENTITY_ID:push
항목을 삭제하려면 다음 엔드포인트에 HTTP DELETE 요청을 전송합니다. 사용하는 인벤토리 스키마에 따라 달라집니다.
v2 인벤토리
https://actions.googleapis.com/v2/apps/PROJECT_ID/entities/TYPE/ENTITY_ID?entity.vertical=FOODORDERING&delete_time=DELETE_TIME
v1 인벤토리
https://actions.googleapis.com/v2/apps/PROJECT_ID/entities/ENTITY_ID?entity.vertical=FOODORDERING&delete_time=DELETE_TIME
위의 요청에서 다음을 바꿉니다.
- PROJECT_ID: 프로젝트와 연결된 Google Cloud 프로젝트 ID입니다. 프로젝트 만들기 및 설정에서 만듭니다.
- TYPE (v2 인벤토리 스키마만 해당): 항목 유형 (
@type
속성) 데이터 피드에 있는 개체의 이름을 입력합니다. - ENTITY_ID: 페이로드에 포함된 항목의 ID입니다. 반드시 URL은 엔티티 ID를 인코딩합니다.
- DELETE_TIME (삭제 엔드포인트만): 배포를 나타내는 선택적 필드
시스템에서 항목이 삭제된 시간입니다. 기본값은 요청이
받았습니다. 시간 값은 미래일 수 없습니다. 엔티티를 전송하는 경우
항목 버전 관리 기능을 통해
삭제 호출의 경우
delete_time
필드도 사용합니다. 형식 지정 값:yyyy-mm-ddTHH:mm:ssZ
예를 들어 ID가 'delivery-provider-id'인 프로젝트가 있습니다. 인코더-디코더 살펴보겠습니다 음식점을 변경할 때 'MenuSection'의 레스토랑 항목 유형 항목 ID 'menuSection_122'가 있습니다. 데이터 업데이트의 엔드포인트는 다음과 같습니다.
https://actions.googleapis.com/v2/apps/delivery-provider-id/entities/MenuSection/menuSection_122:push
동일한 항목을 삭제하려면 다음과 같이 HTTP DELETE API를 호출합니다.
https://actions.googleapis.com/v2/apps/delivery-provider-id/entities/MenuSection/menuSection_122?entity.vertical=FOODORDERING
샌드박스 요청
샌드박스 요청의 경우에는 위의 엔드포인트에 나와 있는 안내를 따릅니다.
/v2/apps/
대신 /v2/sandbox/apps/
에 요청을 전송합니다. 예를 들어
v2 인벤토리 스키마에 대한 샌드박스 삭제 요청의 구조는 다음과 같습니다.
https://actions.googleapis.com/v2/sandbox/apps/PROJECT_ID/entities/TYPE/ENTITY_ID?entity.vertical=FOODORDERING&delete_time=DELETE_TIME
업데이트 및 추가사항
또한 일일 일괄 피드에 API에 액세스할 수 있습니다. 그렇지 않으면 일괄 업데이트가 점진적 변경사항을 덮어씁니다.
페이로드
각 POST 요청에는 JSON 파일과 함께 요청 매개변수가 포함되어야 합니다. 아래 나열된 항목 유형의 구조화된 데이터를 포함하는 페이로드 살펴보겠습니다
JSON은 일괄 피드에서와 동일하게 표시되어야 하며 다음과 같은 차이점이 있습니다.
- 페이로드 본문의 크기는 5MB를 초과해서는 안 됩니다. Batch와 비슷한 피드에서 사용하는 경우 더 많은 데이터를 맞추기 위해 공백을 제거하는 것이 좋습니다.
- 봉투는 다음과 같습니다.
{ "entity": { "data":"ENTITY_DATA", "vertical":"FOODORDERING" }, "update_time":"UPDATE_TIMESTAMP" }
위의 페이로드에서 다음을 바꿉니다.
- ENTITY_DATA: 문자열로 직렬화된 JSON 형식의 항목. 이
JSON-LD 항목은
data
필드에 문자열로 전달되어야 합니다. - UPDATE_TIMESTAMP (선택사항): 항목이 업데이트된 타임스탬프
관리할 수 있습니다 시간 값은 미래일 수 없습니다. 기본 타임스탬프:
Google이 요청을 수신합니다. 증분식을 통해 항목을 전송하는 경우
요청의 경우 항목 버전 관리에서도
추가/업데이트 요청인 경우
update_time
필드입니다.
항목 업데이트
예 1: 식당 업데이트
급하게 식당의 전화번호를 업데이트해야 하는 경우 내 update에는 전체 식당의 JSON이 포함됩니다.
다음과 같은 일괄 피드를 생각해 보세요.
{ "@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 }
그러면 HTTP POST에 의한 증분 업데이트는 다음과 같습니다.
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" } }
예 2: 메뉴 항목 가격 업데이트
메뉴 항목의 가격을 변경해야 한다고 가정해 보겠습니다. 예시 1에서와 같이 업데이트에는 전체 최상위 항목 (메뉴)에 대한 JSON이 포함되어야 하고 피드는 v1 인벤토리 스키마를 사용합니다.
다음과 같은 일괄 피드를 생각해 보세요.
{ "@type": "MenuItemOffer", "@id": "menuitemoffer6680262", "sku": "offer-cola", "menuItemId": "menuitem896532", "price": 3.00, "priceCurrency": "USD" }
그러면 POST를 통한 증분 업데이트는 다음과 같습니다.
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" } }
항목 추가
항목을 추가하려면 인벤토리 업데이트를 사용하지 마세요. 대신 일괄 피드를 v2 인벤토리 스키마에 설명된 대로 이 프로세스를 실행합니다.
항목 삭제
최상위 항목을 삭제하려면 약간 수정된 엔드포인트를 사용합니다. 요청에 HTTP POST 대신 HTTP DELETE를 사용합니다.
다음과 같은 최상위 항목 내의 하위 항목을 삭제하는 데 HTTP DELETE를 사용하지 마세요. 메뉴 항목을 말합니다. 대신 하위 항목 삭제를 하위 항목이 삭제된 최상위 항목으로 업데이트되어야 합니다. 매개변수입니다.
예 1: 최상위 항목 삭제
Google 서비스에서 식당 이름을 사용하는 식당을 삭제하려고 할 때 살펴보겠습니다 해당 서비스와 메뉴도 삭제해야 합니다.
ID가 있는 메뉴 항목의 샘플 엔드포인트 "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
ID가 있는 식당 항목의 샘플 엔드포인트 "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
ID가 있는 서비스 항목의 샘플 엔드포인트 "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
}
예시 2: 하위 항목 삭제
최상위 항목 내에서 하위 항목을 삭제하려면 최상위 항목을 해당 필드에서 하위 항목이 삭제된 항목을 찾습니다. 다음 예시에서는 피드가 v1 인벤토리 스키마를 사용한다고 가정합니다.
예를 들어 서비스 지역을 삭제하려면 해당 서비스 지역으로 서비스를 업데이트하세요.
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"
}
}
API 응답 코드
호출이 성공하면 피드가 유효하거나 정확하다는 의미가 아니라 API를 호출했습니다. 호출이 성공하면 HTTP 응답 코드 200이 다음과 같습니다.
{}
실패한 경우 HTTP 응답 코드는 200이 아니며 응답 본문은 무엇이 잘못되었는지 나타냅니다.
예를 들어 사용자가 '카테고리'를 설정한 경우 봉투의 값을
FAKE_VERTICAL
에게 아래 메시지가 표시됩니다.
{
"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\""
}
]
}
]
}
}
코드 샘플
다음은 다양한 업데이트에서 증분 업데이트 API를 사용하는 방법의 몇 가지 샘플입니다. 있습니다. 이 샘플에서는 Google 인증 라이브러리를 사용하며, 살펴보겠습니다 대안 솔루션은 다음을 참고하세요. 서버 간 애플리케이션에서 OAuth 2.0 사용하기
항목 업데이트
Node.js
이 코드는 Node.js용 Google 인증 라이브러리를 사용합니다.
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
이 코드는 Python용 Google 인증 라이브러리를 사용합니다.
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용 Google 인증 라이브러리를 사용합니다.
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); }
항목 삭제
Node.js
이 코드는 Node.js용 Google 인증 라이브러리를 사용합니다.
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
이 코드는 Python용 Google 인증 라이브러리를 사용합니다.
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용 Google 인증 라이브러리를 사용합니다.
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)); }
사용 사례
다음은 증분 업데이트, 전체 피드 업데이트, 개략적인 내용은 다음과 같습니다.
시나리오 | 최상위 항목 | 설명 및 효과 |
---|---|---|
서비스 사용 중지 | DisabledService |
예기치 않은 이유로 서비스를 사용 중지해야 합니다. 증분 업데이트: 전체 피드: 전체 피드에서 항목을 업데이트해야 합니다.
|
특정 상품의 재고가 없음 | Menu |
증분 업데이트: 캡슐화 Menu 를 전송합니다.
offer.inventoryLevel 가 0으로 설정된 항목
MenuItem 및 기타 모든 데이터는 변경되지 않습니다. |
메뉴 항목 가격 변경 | Menu |
증분 업데이트: 캡슐화 Menu 를 전송합니다.
offer.price 이 지정된 항목의 업데이트된 가격으로 설정된 항목
MenuItem 및 기타 모든 데이터는 변경되지 않습니다. |
새 최상위 항목 추가
|
Menu , Restaurant , Service |
예를 들어 음식점에 새 메뉴를 추가해야 하는 경우 증분 업데이트: 음식점과 함께 새 메뉴 항목을 전송합니다.
필드가 |
최상위 항목을 영구적으로 삭제
|
Menu , Restaurant , Service |
증분 업데이트: 명시적 삭제. 전체 피드: 전체 피드에서 항목을 삭제하기 전에 확인할 수 없습니다. 그렇지 않으면 해당 항목이 다시 추가됩니다. |
특정 Service 에 새 배송 지역 추가 |
Service |
증분 피드: 문제가 되는 Service 항목을
새로운 배송 지역이 포함된 전체 피드 내에서 일반적으로 하는 것처럼 입력란은 그대로 유지됩니다.
Service 의 areaServed 내에 지정됩니다. |
Service 의 배송 예정 도착 시간 업데이트 |
Service |
증분 피드: Service 를
피드(hoursAvailable.deliveryHours 가 업데이트됨)
변경할 수 있습니다 |
Service 에서 배송비 업데이트 |
Service |
증분 피드: 전체 Service 전송:
offers.priceSpecification.price 이(가) 업데이트되었습니다. |
Service 에서 배달 또는 테이크아웃 영업시간 업데이트 |
Service |
증분 피드: Service 를
피드(hoursAvailable 가 업데이트됨)
변경할 수 있습니다 |
Service (최소 주문 금액 변경) |
Service |
증분 피드: 전체 Service 전송:
Service.offers.priceSpecification.eligibleTransactionVolume
업데이트됨 |
MenuItem 완전히 삭제 |
Menu |
증분 피드: Menu
피드하지만 이 MenuItem 이(가) 다음에서 삭제됨
hasMenuItems 목록 |
일괄 작업 및 증분 업데이트 처리 시간에 대한 SLO
일괄 또는 증분 업데이트를 통해 추가된 항목은 다음 시간에서 처리됩니다. 1~2일 배치를 통해 업데이트되거나 삭제된 항목은 2초 후에 처리됩니다. 소요 시간인 반면 증분 업데이트를 통해 업데이트된 항목은 5분 후에 다시 시작합니다. 비활성 항목은 7일 후에 삭제됩니다.
Google에 다음 정보를 보낼 수 있습니다.
- 인벤토리를 최신 상태로 유지하기 위해 하루에 여러 개의 일괄 작업 또는
- 일일 하나의 일괄 작업과 증분 API로 인벤토리를 최신 상태로 유지합니다.