创建并上传 POI Feed
创建和上传 POI Feed 时,请遵循以下说明:
- 对于 POI 数据文件,请遵循 POI Feed 中所述的规范。我们建议您为每次上传使用唯一的 POI 数据文件名。在文件名中添加时间戳,例如
POI_1633621547.json。 - 每天将 Feed 上传到本地 POI SFTP 服务器,以进行完全刷新。
- 您可以在合作伙伴门户的配置 > Feed 部分中找到 SFTP 服务器详细信息。
- 在合作伙伴门户的提取 > 历史记录部分中查看 Feed 提取状态。
Feed 规范
字段要求
VssPoi
表示单个地图注点 (POI) 实体,例如酒店或餐馆。
| 字段名称 | 类型 | 要求 | 说明 |
|---|---|---|---|
poi_id | 字符串 | 必填 | 必需。合作伙伴生成的用于标识 POI 的字符串。 |
name | 对象(Text) | 必填 | 必需。相应 POI 的名称。 |
telephone | 字符串 | POI 的联系电话号码,包括国家/地区代码和区号,例如 +14567891234。 | |
url | 字符串 | 相应 POI 的公共网站的网址。 注意:此信息仅用于匹配目的,不会显示。 | |
location | 对象(GeoCoordinates) | 必填 | 必需。相应 POI 的位置。 |
display_address | 对象(Text) | 界面上显示的地址。 | |
images | 对象数组(Image) | 地图注点的图片。 图片数量上限:5 张。 | |
rating | 数值 | 相应 POI 的平均评分。 | |
num_ratings | 数值 | rating 字段的贡献评分数量。 | |
rating_scale | 数值 | 用于 rating 字段的评分量表。如果最大评分值为 5,则 rating_scale 为 5。 | |
category | 枚举(Category) | 必填 | 必需。表示 POI 的类别。 |
description | 对象(Text) | POI 的说明。 | |
| oneOf(additional_data) | 必填 | 只能设置相应 oneOf 中的一个字段。 |
文本
表示包含本地化内容的文本。
| 字段名称 | 类型 | 要求 | 说明 |
|---|---|---|---|
localizations | 对象数组(LocalizedString) | 本地化字符串。 | |
default_locale | 字符串 | 要用作默认语言的语言区域必须存在于本地化中。 |
LocalizedString
表示本地化字符串。
| 字段名称 | 类型 | 要求 | 说明 |
|---|---|---|---|
locale | 字符串 | 文本的语言标记,例如“en”“en-US”或“sr-Latn”。 | |
text | 字符串 | 指定语言区域中的文本。 |
GeoCoordinates
某一地点的地理位置数据,包括纬度、经度和地址。
| 字段名称 | 类型 | 要求 | 说明 |
|---|---|---|---|
latitude | 数值 | [-90, +90] 度(含边界值)。 如果设置了经度,则为必需;否则为可选。 | |
longitude | 数值 | [-180, +180] 度(含)。 如果设置了纬度,则为必需;否则为可选。 | |
| oneOf(addresses) | 必填 | 只能设置相应 oneOf 中的一个字段。 |
PostalAddress
相应地点的邮政地址。
| 字段名称 | 类型 | 要求 | 说明 |
|---|---|---|---|
country | 字符串 | 必填 | 必需。国家/地区,使用 ISO 3166-1 alpha-2 国家/地区代码,例如“US”。 |
locality | 字符串 | 必填 | 必需。市行政区/城市,例如“山景城”。 |
region | 字符串 | 地区/州/省,例如“CA”。只有在地区通常是地址的一部分的国家/地区才需要填写此字段。(可选) | |
postal_code | 字符串 | 必填 | 必需。邮政编码,例如“94043”。 |
street_address | 字符串 | 必填 | 必需。街道地址,例如“1600 Amphitheatre Pkwy”。 |
图片
表示地图注点 (POI) 的图片。
| 字段名称 | 类型 | 要求 | 说明 |
|---|---|---|---|
url | 字符串 | 图片的网址。Google 会抓取托管在此网址上的媒体。 长度上限:2000。 | |
alt_text | 对象(Text) | 用于无障碍功能的替代文本。 |
HotelData
特定于酒店的 Feed 数据。
| 字段名称 | 类型 | 要求 | 说明 |
|---|---|---|---|
hotel_star_class | 数值 | 官方酒店星级值。 可用于“5 星级酒店”等标签。 此值应为介于 1 到 5 之间的整数。 | |
brand_ids | 字符串数组 | 可展示此酒店的品牌。 如果此字段为空,则酒店可以显示在与 Feed 关联的任何品牌下。 |
LocalData
特定于场所的 Feed 数据。
| 字段名称 | 类型 | 要求 | 说明 |
|---|---|---|---|
business_hours | 对象(BusinessHours) | 场所的正常营业时间。 | |
price_range | 对象(PriceRange) | 商家提供的服务的价格范围。 | |
establishment_category | 对象(Text) | 商家的类型。 | |
brand_landing_pages | 对象数组(BrandLandingPages) | 品牌着陆页。 |
BusinessHours
表示此营业地点正常营业的时间段。 包含 [TimeRange][madden.vss_poi_feed.TimeRange] 实例的集合。 示例:周六的营业时间为 09:00-12:00 和 13:00-17:00: time_ranges { open_day: SATURDAY open_time: { hours: 9, minutes: 0 } close_day: SATURDAY close_time: { hours: 12, minutes: 0 } } time_rages { open_day: SATURDAY open_time: { hours: 13, minutes: 0 } close_day: SATURDAY close_time: { hours: 17, minutes: 0 } } 示例:周六的营业时间为 21:00 至周日 02:00: time_ranges { open_day: SATURDAY open_time: { hours: 21, minutes: 0 } close_day: SUNDAY close_time: { hours: 2, minutes: 0 } }
| 字段名称 | 类型 | 要求 | 说明 |
|---|---|---|---|
time_ranges | 对象数组(TimeRange) | 相应 POI 的营业时间。每个时间段都表示 POI 在一周内正常营业的时段。 |
TimeRange
表示 POI 的营业时间范围,从指定的开始营业日期/时间开始,到指定的结束营业日期/时间结束。 结束营业时间必须在开始营业时间之后,例如当天晚些时候或次日。
| 字段名称 | 类型 | 要求 | 说明 |
|---|---|---|---|
open_day | 枚举(DayOfWeek) | 时间范围的开始日期。 | |
open_time | 对象(TimeOfDay) | 时间范围的开始时间。 | |
close_day | 枚举(DayOfWeek) | 时间范围的结束日期。 | |
close_time | 对象(TimeOfDay) | 时间范围的结束时间。 |
TimeOfDay
| 字段名称 | 类型 | 要求 | 说明 |
|---|---|---|---|
hours | 数值 | 一天中的小时(采用 24 小时制)。必须大于或等于 0,且通常必须小于或等于 23。对于业务结束时间等场景,API 可以选择允许“24:00:00”一值。 | |
minutes | 数值 | 一小时中的分钟数。必须大于或等于 0,且小于或等于 59。 | |
seconds | 数值 | 一分钟中的秒数。必须大于或等于 0,且通常必须小于或等于 59。如果 API 允许闰秒,则 API 可以允许 60 一值。 | |
nanos | 数值 | 秒数的小数部分(以纳秒为单位)。必须大于或等于 0,且小于或等于 999,999,999。 |
PriceRange
POI 提供的服务的价格范围。
| 字段名称 | 类型 | 要求 | 说明 |
|---|---|---|---|
min_price | 对象(Money) | 相应 POI 提供的服务的最低价格。 | |
max_price | 对象(Money) | 相应 POI 提供的服务的最高价格。 |
Money
表示含有货币类型的金额。
| 字段名称 | 类型 | 要求 | 说明 |
|---|---|---|---|
currency_code | 字符串 | 采用 ISO 4217 标准定义的三位字母货币代码。 | |
units | 数值 | 金额的整数单位。
例如,如果 currencyCode 是 "USD",则 1 单位就是一美元。 | |
nanos | 数值 | 以纳单位 (10^-9) 表示的金额数量。
取值范围必须在 -999,999,999 至 +999,999,999 之间(含边界值)。
如果 units 是正数,nanos 必须是正数或零。
如果 units 是零,nanos 可以是正数、零或负数。
如果 units 是负数,nanos 必须是负数或零。
例如,$-1.75 表示为 units=-1 和 nanos=-750,000,000。 |
BrandLandingPages
单个地图注点 (POI) 的本地化品牌着陆页。
| 字段名称 | 类型 | 要求 | 说明 |
|---|---|---|---|
brand_id | 字符串 | 相应配置所适用的品牌。 | |
localized_landing_pages | 对象数组(LocalizedLandingPage) | 本地化着陆页。 url 和 locales 字段值在所有本地化着陆页中必须是唯一的。 | |
default_url | 字符串 | 当任何本地化着陆页都与用户的语言不匹配时,要使用的默认着陆页网址。 |
LocalizedLandingPage
地图注点 (POI) 的本地化着陆页。
| 字段名称 | 类型 | 要求 | 说明 |
|---|---|---|---|
url | 字符串 | 着陆页的网址。 长度上限:2000。 | |
locales | 字符串数组 | 将此页面限制为具有指定语言偏好的用户。 必须包含语言标记,例如“en”“en-US”或“sr-Latn”。 |
类别
表示 POI 的类别。
它应与下面的 additional_data oneof 字段匹配。
| 名称 | 说明 |
|---|---|
UNKNOWN_CATEGORY | |
HOTEL | |
LOCAL |
DayOfWeek
表示星期几。
| 名称 | 说明 |
|---|---|
DAY_OF_WEEK_UNSPECIFIED | 未指定星期几。 |
MONDAY | 星期一 |
TUESDAY | 星期二 |
WEDNESDAY | 星期三 |
THURSDAY | 星期四 |
FRIDAY | 星期五 |
SATURDAY | 星期六 |
SUNDAY | 星期日 |
additional_data
必需。特定于类别的字段。
它应与上方的 category 字段匹配。
| 字段名称 | 类型 | 要求 | 说明 |
|---|---|---|---|
hotel_data | 对象(HotelData) | 与 | 酒店专用字段。 |
local_data | 对象(LocalData) | 与 | 特定于本地的字段。 |
addresses
必需。某个地点的地址。
| 字段名称 | 类型 | 要求 | 说明 |
|---|---|---|---|
address | 对象(PostalAddress) | 营业地点的邮政地址。 |
- 格式:必须为 JPEG、PNG 或 WebP。
- 文件大小上限:每张图片不超过 30 MB。
- 最大尺寸:总像素数不超过 7,500 万(宽度 x 高度 < 75,000,000)。
- 网址类型:指向图片素材资源的直接路径(例如,以 .jpg 结尾)。
- 权限:确保托管服务器允许 Googlebot 或抓取工具访问,并且没有 robots.txt 屏蔽图片目录。
定义
VssPoiFeed 的定义
// Represents a Point of Interest (POI) data feed provided by a partner. export message VssPoiFeed { // The POIs in the feed. repeated VssPoi data = 1; }
VssPoi 定义
// Represents a single Point of Interest (POI) entity e.g. a hotel or // restaurant. export message VssPoi { // Required. A string generated by the partner that identifies a POI. string poi_id = 1; // The entity name, telephone, url and location are used to support // matching partner inventory with entities already present on Google. // Required. The name of the POI. Text name = 2; // The contact telephone number of the POI including its country and // area codes, e.g. +14567891234. string telephone = 3 [(datapol.semantic_type) = ST_PHONE_NUMBER]; // The url of the POI's public website. // Note: This will be used just for matching purposes, not for display. string url = 4; // Required. The location of the POI. GeoCoordinates location = 5; // The address displayed on the UI. Text display_address = 17; // Images of the POI. // Max number of images: 5. repeated Image images = 6; // Average rating for the POI. float rating = 12; // The number of contributing ratings for the `rating` field. int64 num_ratings = 13; // The rating scale used for the `rating` field. If max rating is 5, then // rating_scale is 5. int32 rating_scale = 14; // Represents the category of the POI. // It should match the `additional_data` oneof field below. export enum Category { LOCAL = 4; } // Required. Represents the category of the POI. Category category = 9; // A description of the POI. Text description = 16; // Required. Category specific fields. // It should match the `category` field above. oneof additional_data { // Local specific fields. LocalData local_data = 15; } }
Text 的定义
// Represents a text with localizations. message Text { // Represents a localized string. message LocalizedString { // The text's language tag, such as "en", "en-US" or "sr-Latn". string locale = 1; // The text in the specified locale. string text = 2; } // The localized strings. repeated LocalizedString localizations = 1; // The locale to use as the default language it must be present in the // localizations. string default_locale = 2; }
GeoCoordinates 的定义
// The Geo data of a location, including latitude, longitude, and address. message GeoCoordinates { option (datapol.msg_semantic_type) = ST_LOCATION; // [-90, +90] degrees (inclusive). // Required if longitude is set, otherwise nice to have. double latitude = 1; // [-180, +180] degrees (inclusive). // Required if latitude is set, otherwise nice to have. double longitude = 2; // Required. Address for a location. oneof addresses { // Postal address of the location. PostalAddress address = 3; } }
PostalAddress 的定义
// The postal address for the location. message PostalAddress { option (datapol.msg_semantic_type) = ST_LOCATION; // Required. The country, using ISO 3166-1 alpha-2 country code, e.g. "US". string country = 1; // Required. The locality/city, e.g. "Mountain View". string locality = 2; // The region/state/province, e.g. "CA". This field is only required in // countries where region is commonly a part of the address. (optional) string region = 3; // Required. The postal code, e.g. "94043". string postal_code = 4; // Required. The street address, e.g. "1600 Amphitheatre Pkwy". string street_address = 5; }
图片定义
// Represents an image of the Point of Interest (POI). export message Image { // The url of the image. Google will crawl the media hosted at this URL. // Max length: 2000. string url = 1; // The alternative text to be used for accessibility. Text alt_text = 2; }
LocalData 的定义
// Establishment specific feed data. message LocalData { // The regular business hours of the establishment. BusinessHours business_hours = 1; // Price range of the services offered by the establishment. PriceRange price_range = 2; // The type of establishment. Text establishment_category = 3; // The brand landing pages. repeated BrandLandingPages brand_landing_pages = 4; }
BrandLandingPages 的定义
// The Localized brand landing pages for a single Point of Interest (POI). message BrandLandingPages { // The brand this configuration applies to. string brand_id = 1 [(datapol.semantic_type) = ST_PARTNER_ID]; // Localized landing page for the Point of Interest (POI). message LocalizedLandingPage { // The url of the landing page. // Max length: 2000. string url = 1; // Restricts this page to users with the specified language preference. // Must contain language tags, such as "en", "en-US" or "sr-Latn". repeated string locales = 3; } // The localized landing pages. // The url and locales fields values must be unique across all the localized // landing pages. repeated LocalizedLandingPage localized_landing_pages = 2; // The default landing page url to be used when none of the localized // landing pages matches the user's language. string default_url = 3; }
示例
地图注点 Feed
文件名:poi_1707240000.json
{ "data": [ { "poi_id": "test_restaurant_1", "name": { "localizations": [ { "locale": "en", "text": "Tasty Bites Test Restaurant" } ], "default_locale": "en" }, "telephone": "+1234567890", "url": "https://www.tastybitestest.com", "location": { "latitude": 37.422, "longitude": -122.084, "address": { "country": "US", "locality": "Mountain View", "postal_code": "94043", "street_address": "1600 Amphitheatre Pkwy" } }, "display_address": { "localizations": [ { "locale": "en", "text": "1600 Amphitheatre Pkwy, Mountain View, CA 94043" } ], "default_locale": "en" }, "images": [ { "url": "https://www.tastybitestest.com/images/interior.jpg", "alt_text": { "localizations": [ { "locale": "en", "text": "Cozy dining area of Tasty Bites" } ], "default_locale": "en" } } ], "rating": 4.7, "num_ratings": 150, "rating_scale": 5, "category": "LOCAL", "description": { "localizations": [ { "locale": "en", "text": "A mock restaurant for testing the POI feed ingestion." } ], "default_locale": "en" }, "local_data": { "establishment_category": { "localizations": [ { "locale": "en", "text": "Restaurant" } ], "default_locale": "en" }, "price_range": { "min_price": { "currency_code": "USD", "units": 15, "nanos": 0 }, "max_price": { "currency_code": "USD", "units": 45, "nanos": 0 } }, "business_hours": { "time_ranges": [ { "open_day": "MONDAY", "open_time": { "hours": 11, "minutes": 0 }, "close_day": "MONDAY", "close_time": { "hours": 21, "minutes": 0 } }, { "open_day": "TUESDAY", "open_time": { "hours": 11, "minutes": 0 }, "close_day": "TUESDAY", "close_time": { "hours": 21, "minutes": 0 } }, { "open_day": "WEDNESDAY", "open_time": { "hours": 11, "minutes": 0 }, "close_day": "WEDNESDAY", "close_time": { "hours": 21, "minutes": 0 } }, { "open_day": "THURSDAY", "open_time": { "hours": 11, "minutes": 0 }, "close_day": "THURSDAY", "close_time": { "hours": 22, "minutes": 0 } }, { "open_day": "FRIDAY", "open_time": { "hours": 11, "minutes": 0 }, "close_day": "FRIDAY", "close_time": { "hours": 23, "minutes": 0 } }, { "open_day": "SATURDAY", "open_time": { "hours": 10, "minutes": 0 }, "close_day": "SATURDAY", "close_time": { "hours": 23, "minutes": 0 } }, { "open_day": "SUNDAY", "open_time": { "hours": 10, "minutes": 0 }, "close_day": "SUNDAY", "close_time": { "hours": 20, "minutes": 0 } } ] }, "brand_landing_pages": [ { "brand_id": "tasty_bites_brand", "localized_landing_pages": [ { "url": "https://www.tastybitestest.com/en", "locales": ["en-US", "en-GB"] } ], "default_url": "https://www.tastybitestest.com" }, { "brand_id": "delicious_eats_brand", "localized_landing_pages": [ { "url": "https://www.deliciouseats.com/en", "locales": ["en-US", "en-GB"] } ], "default_url": "https://www.deliciouseats.com" } ] } } ] }
多语言地图注点 Feed
文件名:poi_multilingual.json
{ "data": [ { "poi_id": "test_restaurant_1", "name": { "localizations": [ { "locale": "en", "text": "Tasty Bites Test Restaurant" }, { "locale": "fr", "text": "Restaurant de test Tasty Bites" } ], "default_locale": "en" }, "telephone": "+1234567890", "url": "https://www.tastybitestest.com", "location": { "latitude": 37.422, "longitude": -122.084, "address": { "country": "US", "locality": "Mountain View", "postal_code": "94043", "street_address": "1600 Amphitheatre Pkwy" } }, "display_address": { "localizations": [ { "locale": "en", "text": "1600 Amphitheatre Pkwy, Mountain View, CA 94043" }, { "locale": "fr", "text": "1600 Amphitheatre Pkwy, Mountain View, CA 94043" } ], "default_locale": "en" }, "images": [ { "url": "https://www.tastybitestest.com/images/interior.jpg", "alt_text": { "localizations": [ { "locale": "en", "text": "Cozy dining area of Tasty Bites" }, { "locale": "fr", "text": "Espace salle à manger accueillant de Tasty Bites" } ], "default_locale": "en" } } ], "rating": 4.7, "num_ratings": 150, "rating_scale": 5, "category": "LOCAL", "description": { "localizations": [ { "locale": "en", "text": "A mock restaurant for testing the POI feed ingestion." }, { "locale": "fr", "text": "Un faux restaurant pour tester l'ingestion de flux de points d'intérêt." } ], "default_locale": "en" }, "local_data": { "establishment_category": { "localizations": [ { "locale": "en", "text": "Restaurant" }, { "locale": "fr", "text": "Restaurant" } ], "default_locale": "en" }, "price_range": { "min_price": { "currency_code": "USD", "units": 15, "nanos": 0 }, "max_price": { "currency_code": "USD", "units": 45, "nanos": 0 } }, "business_hours": { "time_ranges": [ { "open_day": "MONDAY", "open_time": { "hours": 11, "minutes": 0 }, "close_day": "MONDAY", "close_time": { "hours": 21, "minutes": 0 } }, { "open_day": "TUESDAY", "open_time": { "hours": 11, "minutes": 0 }, "close_day": "TUESDAY", "close_time": { "hours": 21, "minutes": 0 } }, { "open_day": "WEDNESDAY", "open_time": { "hours": 11, "minutes": 0 }, "close_day": "WEDNESDAY", "close_time": { "hours": 21, "minutes": 0 } }, { "open_day": "THURSDAY", "open_time": { "hours": 11, "minutes": 0 }, "close_day": "THURSDAY", "close_time": { "hours": 22, "minutes": 0 } }, { "open_day": "FRIDAY", "open_time": { "hours": 11, "minutes": 0 }, "close_day": "FRIDAY", "close_time": { "hours": 23, "minutes": 0 } }, { "open_day": "SATURDAY", "open_time": { "hours": 10, "minutes": 0 }, "close_day": "SATURDAY", "close_time": { "hours": 23, "minutes": 0 } }, { "open_day": "SUNDAY", "open_time": { "hours": 10, "minutes": 0 }, "close_day": "SUNDAY", "close_time": { "hours": 20, "minutes": 0 } } ] }, "brand_landing_pages": [ { "brand_id": "tasty_bites_brand", "localized_landing_pages": [ { "url": "https://www.tastybitestest.com/fr", "locales": ["fr-FR", "fr-CA"] }, { "url": "https://www.tastybitestest.com/en", "locales": ["en-US", "en-GB"] } ], "default_url": "https://www.tastybitestest.com" }, { "brand_id": "delicious_eats_brand", "localized_landing_pages": [ { "url": "https://www.deliciouseats.com/fr", "locales": ["fr-FR", "fr-CA"] }, { "url": "https://www.deliciouseats.com/en", "locales": ["en-US", "en-GB"] } ], "default_url": "https://www.deliciouseats.com" } ] } } ] }