返回

AWS Location营业时间获取不到? 查看原因和解决方法

java

AWS Location Service 获取地点营业时间?没那么简单!

你是不是也在用 AWS Location Service 获取地点信息?用着官方示例代码,满心欢喜地以为 GetPlace API 能顺便把营业时间也给带回来?结果发现,欸?怎么没回传 hours 字段,明明 AWS 控制台里的那个演示 Web App 上面都显示了啊!

就像下面这段常见的代码:先用 searchPlaceIndexForText 找地点,拿到 PlaceId,再调用 getPlace 获取详细信息。

    // 根据参数构建搜索文本
    String searchText = String.format("%s %s %s %s", name, addressLine1, city, state);

    // 创建搜索请求
    SearchPlaceIndexForTextRequest searchRequest = SearchPlaceIndexForTextRequest.builder()
            .indexName(placesIndex) // 你的地点索引名称
            .text(searchText)
            .build();

    // 执行搜索
    SearchPlaceIndexForTextResponse searchResponse = locationClient.searchPlaceIndexForText(searchRequest);

    if (searchResponse.hasResults() && !searchResponse.results().isEmpty()) {
        // 获取第一个结果的 Place ID
        // 注意:实际应用中可能需要更复杂的逻辑来选择最佳匹配项
        Optional<SearchForTextResult> firstResult = searchResponse.results().stream().findFirst();

        if (firstResult.isPresent()) {
            String placeId = firstResult.get().placeId();
            System.out.println("找到 Place ID: " + placeId);

            // 创建 GetPlace 请求
            GetPlaceRequest placeRequest = GetPlaceRequest.builder()
                    .placeId(placeId)
                    .indexName(placesIndex) // 同样需要地点索引名称
                    .language("zh")  // 指定响应语言,例如中文
                    .build();

            // 获取地点详情
            GetPlaceResponse placeResponse = locationClient.getPlace(placeRequest);

            // 处理地点详情 (下面会看到这里可能没有 hours)
            System.out.println("地点详情: " + placeResponse.place());
             // 这里通常你会尝试访问 placeResponse.place().hours() 或者类似字段,但很可能找不到
        }
    } else {
        System.out.println("未找到匹配的地点。");
    }

跑完之后,比如你搜了个麦当劳,拿到的 JSON 响应大概是这个样子(为了清晰,我格式化了一下):

{
  "place": {
    "addressNumber": "510",
    "categories": [
      "PointOfInterestType"
    ],
    "country": "USA",
    "geometry": {
      "point": [
        -116.2429,
        43.60939
      ]
    },
    "interpolated": false,
    "label": "McDonald's, 510 N Orchard St, Boise, ID 83706-1979, United States",
    "municipality": "Boise",
    "neighborhood": "Morris Hill",
    "postalCode": "83706-1979",
    "region": "Idaho",
    "street": "N Orchard St",
    "subRegion": "Ada",
    "supplementalCategories": [
      "Fast Food"
    ],
    "timeZone": {
      "name": "America/Boise",
      "offset": -25200
    }
    // 注意!这里通常没有 'hours''openingHours' 字段
  }
}

但官方那个演示 App 明明就能显示营业时间,比如下面这张图里的样子:

官方演示App显示营业时间

这就让人迷惑了,难道 GetPlace API 真的不能返回营业时间吗?

症结所在:GetPlace 的 “局限性”

直接告诉你答案:通常情况下,GetPlace API 本身,确实不会直接返回结构化的营业时间信息。

为什么?主要原因有几个:

  1. 数据源依赖性: AWS Location Service 本身不生产数据,它是个聚合器。它背后的数据来自不同的提供商,比如 Esri、HERE、Grab 等。你创建 Place Index(地点索引)时,需要选择一个数据源。
    • 关键点: 营业时间这类信息,并非所有数据提供商都会提供,或者说,并非所有提供商都会通过 AWS Location Service 这个渠道 完整地 暴露出来。
    • 有些数据可能被认为是“高级”或“附加”信息,在标准的 GetPlace 响应中可能不包含。
  2. API 设计焦点: GetPlace 的核心目标是提供一个地点的权威、核心的地理空间信息(坐标、地址、类别、时区等)。营业时间虽然重要,但它相对动态,且数据可用性差异很大,可能被设计成了非核心返回项。
  3. 演示 App 的 “魔法”? 那个演示 App 能够显示营业时间,可能存在几种情况:
    • 它使用了特定配置的 Place Index,其背后的数据源(例如 HERE)恰好通过某种方式提供了这部分数据(即使标准的 GetPlace API 响应里没有直接字段)。
    • 它可能在后台调用了其他内部或未公开的 API。
    • 它可能结合了 AWS Location Service 和其他第三方服务(比如直接调用 HERE 或 Esri 的特定 API)来获取更丰富的数据。
    • 或者,最有可能的情况是,它依赖的数据提供商(比如你在创建 Place Index 时选择了 HERE 或 Esri),而 那些 提供商的数据集里包含了营业时间。但 AWS 的 GetPlace SDK/API 并没有将这个字段标准化地暴露出来。

所以,问题不在于你的代码写错了,而是 GetPlace API 的标准响应结构,通常不包含 hours 这个字段。

怎么办?绕开障碍获取营业时间

既然直接走 GetPlace 这条路可能行不通,我们就得想想别的办法。

方案一:确认你的数据源并查阅其文档

这是最先应该尝试的步骤。你需要知道你用的 Place Index 背后是哪个大佬在提供数据。

  1. 如何确认数据源?

    • AWS 管理控制台:
      • 打开 AWS 管理控制台,导航到 Location Service。
      • 在左侧菜单选择 “地点索引 (Place indexes)”。
      • 找到你使用的索引名称,点击进入详情页。
      • 在 “详情 (Details)” 部分,查看 “数据提供商 (Data provider)” 字段。你会看到是 Esri, HERE, Grab 还是其他。
    • AWS CLI:
      如果你喜欢用命令行,可以执行以下命令(将 YourIndexName 替换成你的索引名称):
      aws location describe-place-index --index-name YourIndexName
      
      在返回的 JSON 中查找 DataSource 字段。
  2. 查阅数据源文档(关键步骤!)

    • 知道了数据源(比如是 HERE 或 Esri),下一步就是去这个 具体 数据提供商的官方开发者文档里查找。
    • 搜索重点: 他们的 Places API 或 POI (Point of Interest) API 是否提供营业时间(Opening Hours)?是通过哪个 API 端点或参数获取的?
    • 注意: 即使他们的 API 提供营业时间,这 意味着 AWS Location Service 的 GetPlace 一定 会把它包含进来。你需要关注的是,他们的数据集里 是否包含 这类信息。如果数据源本身就没有某个地点的营业时间,那 AWS 自然也无从提供。

这个方案的原理和作用:
弄清楚数据的真正来源。如果源头(Esri 或 HERE)的数据集里压根就没有你要的营业时间信息,那强求 AWS Location Service 也是徒劳。如果源头 ,但 AWS 没直接提供,那就得考虑下面的方案了。

安全建议:
此步骤主要涉及信息查询,不直接涉及敏感操作。

方案二:直接调用数据提供商的 API (进阶)

如果确认了你的数据源(比如 HERE)确实提供营业时间信息,但 AWS Location Service 的 GetPlace 没给,你可以考虑“绕过” AWS Location Service 的标准 API,直接去调用那个数据提供商(HERE)自己的 Places API。

这通常意味着你需要:

  1. 注册数据提供商开发者账号: 去 Esri 或 HERE 的开发者门户网站注册账号。
  2. 获取 API 密钥: 根据他们的流程申请并获取用于访问其 API 的密钥 (API Key) 或凭证。
  3. 学习他们的 API 和 SDK: 阅读他们的 API 文档,了解如何调用他们的地点搜索或地点详情接口来获取包括营业时间在内的详细信息。通常他们会提供不同语言的 SDK。
  4. 在你的应用中集成:
    • 你仍然可以使用 AWS Location Service 的 SearchPlaceIndexForText 来进行初步搜索,获取地点的基本信息和坐标,甚至可能是提供商自己的 Place ID (某些情况下 GetPlace 响应里可能包含原始提供商的 ID)。
    • 然后,使用从 AWS 获取到的信息(如坐标或名称),调用数据提供商(Esri/HERE)的 API 来查询更详细的信息,这次明确请求包含营业时间。

示例(概念性 Python 代码 - 以假设的 HERE API 为例):

# 假设你已经通过 AWS Location Service 获取了地点的坐标 (latitude, longitude)
# 或者获取到了 HERE 的 Place ID (如果 GetPlace 返回了)

import requests
import json

here_api_key = 'YOUR_HERE_API_KEY' # 从 HERE Developer Portal 获取
latitude = 43.60939
longitude = -116.2429

# 使用 HERE Geocoding and Search API v7 的 'lookup' 端点 (需要查阅最新文档确认)
# 或者 'browse'/'discover' 端点配合坐标和类别
# 这里用 lookup 假设你知道了 HERE Place ID (需要确认 GetPlace 是否返回或有其他途径获取)
# lookup_url = f"https://lookup.search.hereapi.com/v1/lookup?id=HERE_PLACE_ID&apiKey={here_api_key}&resultType=place"

# 或者,如果用坐标反向查找,可能用 'revgeocode' 或 'discover'
# 这里用 discover 示例 (具体参数请查阅 HERE 文档)
discover_url = f"https://discover.search.hereapi.com/v1/discover?at={latitude},{longitude}&q=McDonalds&limit=1&apiKey={here_api_key}&show=openingHours"
# 注意: 'show=openingHours' 或类似参数是关键,需要查阅文档确认如何请求特定字段

try:
    response = requests.get(discover_url)
    response.raise_for_status() # 如果请求失败则抛出异常

    data = response.json()

    # 解析响应,查找营业时间字段
    # HERE API 返回的结构可能类似这样 (需要根据实际文档调整):
    if 'items' in data and data['items']:
        place_details = data['items'][0]
        if 'openingHours' in place_details:
            print("营业时间信息:")
            print(json.dumps(place_details['openingHours'], indent=2))
        else:
            print("在此地点未找到营业时间信息。")
    else:
         print("未找到匹配的地点详情。")

except requests.exceptions.RequestException as e:
    print(f"请求 HERE API 时出错: {e}")
except json.JSONDecodeError:
    print("解析 HERE API 响应时出错。")
except KeyError as e:
    print(f"处理 HERE API 响应时缺少键: {e}")

原理和作用:
直接与数据源头对话。数据提供商自己的 API 通常比 AWS Location Service 聚合后的 API 提供更丰富、更细粒度的字段选项,更有可能获取到营业时间等附加信息。

安全建议:

  • 保护好你的 API 密钥! 这是直接访问数据提供商服务的凭证,泄露可能导致未授权访问和潜在的费用。不要硬编码在代码里,使用环境变量、Secrets Manager 或其他安全方式存储和管理。
  • 注意使用配额和成本: 直接调用提供商 API 通常有自己的调用限制和计费模式,可能与 AWS Location Service 不同,需要仔细阅读其定价和服务条款。

进阶使用技巧:

  • 字段选择 (Field Selection): 许多提供商 API 允许你指定只返回你需要的字段(比如 fields=geometry,openingHours),这样可以减少响应体积,节省带宽,也可能降低成本。仔细阅读文档,看是否支持。
  • 缓存: 对于不常变化的地点信息(比如地址),可以考虑缓存结果,减少对外部 API 的调用次数。但营业时间可能会变动(节假日调整等),缓存时要注意设置合理的过期时间。

方案三:使用专门的第三方地点数据服务

除了 AWS Location Service 的数据源(Esri, HERE 等),市面上还有其他专注于提供丰富 POI (Point of Interest) 数据的服务,比如 Google Places API、Foursquare Places API 等。

这些服务通常将获取包括营业时间在内的详细商业信息作为核心功能之一。

  1. 选择服务并注册: 比较不同服务的功能、覆盖范围、定价,选择合适的并注册开发者账号。
  2. 获取 API 密钥: 获取访问其服务的 API 密钥。
  3. 集成 API/SDK: 使用他们提供的 SDK 或直接调用 HTTP API。通常,你可以用地点名称和地址,或者坐标来搜索地点,然后在请求中指明需要返回营业时间信息。

示例(概念性 - 调用类似 Google Places API 的服务):

// 假设在一个 Node.js 环境中使用 Google Maps Platform Services
// 需要安装 @googlemaps/google-maps-services-js

const { Client } = require("@googlemaps/google-maps-services-js");

const client = new Client({});
const apiKey = 'YOUR_GOOGLE_PLACES_API_KEY'; // 从 Google Cloud Console 获取

async function getPlaceHours(query) {
  try {
    const findPlaceResponse = await client.findPlaceFromText({
      params: {
        input: query, // 例如 "McDonalds 510 N Orchard St Boise"
        inputtype: 'textquery',
        fields: ['place_id'], // 先只获取 place_id
        key: apiKey,
      },
      timeout: 1000, // milliseconds
    });

    if (findPlaceResponse.data.candidates && findPlaceResponse.data.candidates.length > 0) {
      const placeId = findPlaceResponse.data.candidates[0].place_id;
      console.log("找到 Google Place ID:", placeId);

      // 使用 Place ID 获取详细信息,明确要求 opening_hours
      const placeDetailsResponse = await client.placeDetails({
        params: {
          place_id: placeId,
          fields: ['name', 'formatted_address', 'opening_hours', 'geometry'], // 明确包含 'opening_hours'
          key: apiKey,
        },
        timeout: 1000,
      });

      if (placeDetailsResponse.data.result) {
          const details = placeDetailsResponse.data.result;
          console.log("地点名称:", details.name);
          console.log("地址:", details.formatted_address);
          if (details.opening_hours) {
              console.log("营业时间状态:", details.opening_hours.open_now ? "现在营业" : "现在关闭");
              console.log("平日文本:", details.opening_hours.weekday_text);
              // details.opening_hours.periods 包含结构化的营业时间数据
              console.log("结构化营业时间:", JSON.stringify(details.opening_hours.periods, null, 2));
          } else {
              console.log("未找到该地点的营业时间信息。");
          }
      } else {
          console.log("未能获取地点详情。");
      }

    } else {
      console.log("未找到匹配的地点。");
    }
  } catch (error) {
    console.error("调用 Google Places API 时出错:", error.response ? error.response.data : error.message);
  }
}

// 调用示例
getPlaceHours("McDonalds 510 N Orchard St Boise ID");

原理和作用:
利用那些专门为提供丰富 POI 数据(包括营业时间、评论、照片等)而设计的商业服务。它们通常在这方面做得更专业,数据更新也可能更频繁。

安全建议:

  • API 密钥管理: 同样,保护好你的 API 密钥至关重要。
  • 成本考虑: 这些第三方服务通常有更明确的按请求量或功能计费的模式,务必了解清楚其定价策略,避免意外账单。Google Places API 等服务有免费额度,但超出后会收费。
  • 使用条款: 仔细阅读服务条款,特别是关于数据使用、展示(比如是否需要在地图上显示 Google Logo)等方面的规定。

进阶使用技巧:

  • 组合使用: 可以结合 AWS Location Service 进行地理编码或初步搜索,然后使用获取到的坐标或地址信息去调用第三方服务获取更丰富的详情(如营业时间、评价等),取长补短。
  • 错误处理和回退: 如果一个服务未能返回营业时间,可以尝试调用另一个备选服务,或者优雅地向用户显示“营业时间未知”。

方案四:自己动手,丰衣足食 (下策)

如果上述方法都不理想,或者你需要的地点非常有限且固定,还有一个不得已的选择:

  1. 手动收集: 对于你业务中至关重要的少量地点,派人去核实或查找官方网站,手动收集营业时间。
  2. 数据存储: 将这些信息存储在你自己的数据库中(比如 DynamoDB、RDS 或一个简单的配置文件)。
  3. 查询逻辑: 在你的应用逻辑中,当需要显示某个地点的营业时间时,优先查询你自己的数据库。

原理和作用:
简单粗暴,对于特定场景(例如只关心自己公司的几个门店)可能成本最低、最可控。

缺点:

  • 扩展性差:地点一多就完全不可行。
  • 维护成本高:营业时间会变(节假日、临时调整),需要持续更新维护,否则数据会过时。
  • 不适用于需要大范围、动态查询地点的应用。

总而言之,想用 AWS Location Service 直接通过 GetPlace API 拿到营业时间,目前来看多半是行不通的。你需要深入了解你的数据来源,或者考虑集成数据提供商自己的 API,甚至是采用专门的第三方地点服务。根据你的具体需求、预算和技术能力,选择最适合你的那条路吧!