Skip to content

搜索

search 包提供了与搜索相关的全部类。Search 是这套 API 中能力最强、灵活度最高的部分。下面是其提供的主要搜索能力:

  • Onebox search — 基于位置的语义搜索,可通过自由文本或带标签的查询语法查找 POI(兴趣点)和地址。借助底层先进的语义理解能力,开发者只需在一个文本框(one-box)中输入自由文本就能获得高度相关的结果。它是 Telenav 搜索能力的基础,也提供了最高的灵活性。
  • Category filter search — 按指定类目搜索 POI。Telenav 支持超过 100 个 POI 类目。
  • Brand filter search — 按指定品牌或连锁名搜索 POI。
  • Corridor search — 在指定路径走廊范围内查找 POI,也叫"沿途搜索(Search Along Route)",用于将结果限定在驾驶路线附近。
  • Polygon search — 将结果限定在任意多边形区域内。
  • Bounding box search — 将结果限定在一个矩形包围盒内。
  • Reverse geocoding (RGC) — 根据坐标(经纬度)反向解析出地址。
  • Voice Search — 支持自由文本和结构化文本查询,适用于语音搜索场景。
  • Electric vehicle charge station search — 面向电动车充电站的专用搜索能力。
  • Anchor search — 当搜索位置与当前车辆位置不同时,用于显式指定搜索位置。
  • Exit Search - 在指定位置附近,针对一个或多个 出口点 / 休息区(ExitPoint),查询指定 品类(Category) 的 POI 可用情况。

主要的 Search 相关类请参见 API reference

通用请求参数

Search API 通过 entityClient.searchRequest() 构建请求。除下文各搜索场景单独说明的参数外,还可设置以下通用参数:

方法 说明
setLocation(double latitude, double longitude) 当前车辆位置坐标。若未设置 anchor,则同时作为搜索锚点。必填
setAnchor(double latitude, double longitude) 搜索锚点坐标。与 location 同时设置时,location 用于计算驾驶距离和驾驶时间,anchor 用于搜索。选填
setQuery(String query) 自由文本查询,支持 onebox 和 multibox 语法。选填
setQuery(MultiboxQuery multiboxQuery) 结构化多框查询,通常配合语音搜索使用。选填
setLimit(Integer limit) 返回结果数量,默认值 10。选填
setLocale(Locale locale) 响应内容的语言偏好,例如 Locale.US选填
setPageContext(String pageContext) 分页上下文,用于获取下一页结果。传入后其他参数将被忽略, pageContext 从上一个搜索的Response里获取。response.getPaginationContext().getNextPageContext()。选填
setSearchOptions(SearchOptions options) 搜索选项,用于自定义搜索行为。选填
setFilters(SearchFilters filters) 搜索过滤器(地理、类目、品牌、EV 等)。选填
setFacetParameters(FacetParameters facetParameters) facet 相关参数,例如停车价格估算。选填
setSort(SortType sortType) 设置排序方式, 支持 BEST_MATCH 和 DISTANCE。例如: setSort(SortType.DISTANCE)。选填

SearchOptions

通过 SearchOptions.builder() 构建后,经 setSearchOptions() 传入:

方法 说明
setIntent(SearchOptions.Intent intent) 搜索意图。支持:AROUND(默认,基于位置查找相关 entity)、NEAR_DESTINATION(在目的地附近查找)、PREDICTION(基于用户画像的预测,暂不支持)、REVERSE_GEOCODING(逆地理编码)
setShowAddressLines(Boolean showAddressLines) 设为 true 时,响应中返回分行格式化的 address_lines
setTrigger(SearchOptions.Trigger trigger) 触发特殊搜索类型。语音搜索设为 SearchOptions.Trigger.VOICE

FacetParameters

通过 FacetParameters.builder() 构建后,经 setFacetParameters() 传入:

方法 说明
setParkingParameters(ParkingParameters parameters) 停车参数,用于价格估算。entry_time 格式为 yyyy-MM-ddTHH:mmyyyy-MM-ddTHH:mmZ(带 Z 表示 UTC,否则按本地时间处理);duration 为停车时长(分钟),默认 60
setFacetFieldParameters(FacetFieldParameters parameters) 指定返回的结果 facet 类型,如 CHARGER_BRANDPOWER_FEED_LEVEL
addAdditionalFacetAttribute(AdditionalFacetAttributeType type) 额外 facet 属性,如 LINKED_ENTITY

当输入是一段自由文本、搜索区域是某个点附近时,使用 one box search。开发者至少需要提供查询文本和一个位置点。Telenav one box search 是基于语义的自由文本查询能力,通过 .setQuery 方法传入一段文本,即可搜索多种 entity 类型。同时它具备模糊匹配能力,输入文本不必与目标 entity 完全一致。one box 文本解析器可从自由文本中识别以下 entity 类型:

  • 地址(完整或部分)
  • 兴趣点(精确或近似匹配)
  • 类目名(包括同义词)
  • 街道(带或不带街道后缀)
  • 城市

除以上 entity 类型外,还支持更复杂的查询模式,例如查询路口、"在某城市内某 POI"等。

Fuzzy one box:查询文本不必精确,语义搜索会考虑近似名称以及与目标名称相近的"模糊匹配"entity。

关键方法

方法 说明
setLocation(double latitude, double longitude) 用户当前位置(地理坐标 latitude, longitude)。若未设置 anchor,则同时作为搜索锚点。必填
setQuery(String query) 自由文本查询。可用于搜索地址、POI、街道或城市,同时支持更复杂的查询模式。查询模式按 locale 本地化。选填
setLimit(Integer limit) 返回结果数量,默认值 10。选填
setLocale(Locale locale) 响应内容的语言偏好。选填
setSearchOptions(SearchOptions options) 搜索选项,例如设置 show_address_lines 返回分行地址。选填


Search API 示例代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
entityClient.searchRequest()
    .setQuery("Pierce Rd")
    .setLocation(37.12419, -121.98828)
    .asyncCall(new Callback<EntitySearchResponse>() {

        @Override
        public void onSuccess(EntitySearchResponse response) {
            // 以 JSON 格式打印响应
            LOG.info(EntityJsonConverter.toPrettyJson(response));

            List<Entity> resultEntities = response.getResults();
            if (resultEntities == null || resultEntities.isEmpty()) {
                LOG.info("No result found");
                return;
            }
            for (Entity entity : resultEntities) {
                if (entity.getType() == EntityType.ADDRESS) {
                    LOG.info("Found Address: " + entity.getAddress().getFormattedAddress());
                } else if (entity.getType() == EntityType.PLACE) {
                    LOG.info("Found Place: " + entity.getPlace().getName());
                }
            }
        }

        @Override
        public void onFailure(Throwable t) {
            LOG.error("Get unsuccessful response or throwable happened when executing the request.", t);
        }
    });
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
entityClient.searchRequest()
    .setQuery("Pierce Rd")
    .setLocation(37.12419, -121.98828)
    .asyncCall(object : Callback<EntitySearchResponse> {

        override fun onSuccess(response: EntitySearchResponse) {
            // 以 JSON 格式打印响应
            Log.i("sdk", EntityJsonConverter.toPrettyJson(response))

            val resultEntities = response.results
            if (resultEntities == null || resultEntities.isEmpty()) {
                Log.i("sdk", "No result found")
                return
            }
            for (entity in resultEntities) {
                if (entity.type == EntityType.ADDRESS) {
                    Log.i("sdk", "Found Address: ${entity.address.formattedAddress}")
                } else if (entity.type == EntityType.PLACE) {
                    Log.i("sdk", "Found Place: ${entity.place.name}")
                }
            }
        }

        override fun onFailure(t: Throwable) {
            Log.e("sdk", "Get unsuccessful response or throwable happened when executing the request.", t)
        }
    })

也可以使用 execute() 方法以同步方式调用 API。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
EntitySearchResponse response = null;
try {
    response = entityClient.searchRequest()
        .setQuery("Pierce Rd")
        .setLocation(37.12419, -121.98828)
        .execute();
} catch (IOException e) {
    LOG.error("Error happened when doing search.", e);
    return;
} catch (EntityServiceException e) {
    ResponseCode code = e.getCode();
    LOG.error("Error happened when doing search. error code={}", code.getStatusCode(), e);
    return;
}

List<Entity> resultEntities = response.getResults();
if (resultEntities == null || resultEntities.isEmpty()) {
    LOG.info("No result found.");
    return;
}
for (Entity entity : resultEntities) {
    if (entity.getType() == EntityType.ADDRESS) {
        LOG.info("Found Address: " + entity.getAddress().getFormattedAddress());
    } else if (entity.getType() == EntityType.PLACE) {
        LOG.info("Found Place: " + entity.getPlace().getName());
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
var response: EntitySearchResponse?

response = try {
    entityClient.buildSearchRequest()
        .setQuery("Pierce Rd")
        .setLocation(37.12419, -121.98828)
        .execute()
} catch (e: IOException) {
    Log.e("sdk", "Error happened when doing search.", e)
    return
} catch (e: EntityServiceException) {
    val code: ResponseCode = e.getCode()
    Log.e("sdk", "Error happened when doing search. error code=${code.statusCode}", e)
    return
}

val resultEntities = response.results
if (resultEntities == null || resultEntities.isEmpty()) {
    Log.i("sdk", "No result found.")
    return
}
for (entity in resultEntities) {
    if (entity.type == EntityType.ADDRESS) {
        Log.i("sdk", "Found Address: ${entity.address.formattedAddress}")
    } else if (entity.type == EntityType.PLACE) {
        Log.i("sdk", "Found Place: ${entity.place.name}")
    }
}

响应示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
{
  "code": "SUCCESS",
  "reference_id": "2e3f55e3-df3e-44d4-8b88-b120630274b9",
  "search_metadata": {
    "counts": [
      {
        "type": "ADDRESS",
        "count": 3
      }
    ],
    "query_resolution": {
      "query_tags": [
        {
          "where": "Street=Pierce Rd"
        }
      ],
      "search_location": {
        "latitude": 37.12419,
        "longitude": -121.98828
      }
    }
  },
  "has_more": false,
  "results": [
    {
      "id": "Yz1Mb3MgR2F0b3M7Y3k9U2FudGEgQ3J1ejtjbz1VUztzZm49UGllcmNlIFJkO3o9OTUwMzM7cz1DQTt0PVNUUkVFVDtpZD1IM19OVF9iQ2RoUnBxUEF1UmhVMGxySGJrMDRBO2x0PTM3LjEyNjAyO2xuPS0xMjEuOTkwMzY7cmdjPWZhbHNlO3R0PVNUUkVFVDtpX2NvPVVTO2lfc2ZuPVBpZXJjZSBSZDsV6",
      "type": "ADDRESS",
      "address": {
        "address_type": "STREET",
        "formatted_address": "Pierce Rd, Los Gatos CA 95033, USA",
        "street": {
          "body": "pierce",
          "type": "road",
          "formatted_name": "Pierce Rd"
        },
        "city": "Los Gatos",
        "county": "Santa Cruz",
        "state": "CA",
        "country": "USA",
        "postal_code": "95033",
        "geo_coordinates": {
          "latitude": 37.12602,
          "longitude": -121.99036
        },
        "nav_coordinates": {
          "latitude": 37.12602,
          "longitude": -121.99036
        }
      },
      "distance": 274.0
    },
    ...
  ],
  "response_time": 58
}

Category filter search 用于在指定位置周围按指定类目进行搜索。调用时开发者需要提供一个 category id 列表,以及一个地理坐标作为位置。

该能力常用于 HMI 包含一组按钮或类目层级界面、由用户选择目标 POI 类目(如餐厅、加油、停车等)的场景。

Telenav 的 POI 类目采用层级模型,包含父节点与子节点。子节点只会返回属于该节点类目的 POI;如果传入父类目,则返回该父类目下所有子节点对应的 POI。例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Parent (2041)
    Restaurant (226)
        Steakhouse (267)
        Pizza (263)
        Mexican (261)
        ....
    Coffee and Bakery (890)
        Bagels and Donuts (230)
        Bakeries (231)
        Coffee (241)

在上面的类目示例中:传入 category id 2041,结果会包含所有餐厅以及咖啡/烘焙类 POI;传入 226,结果包含各种菜系/风格的餐厅 POI;传入 263,则结果只包含 Pizza 类 POI。

类目列表及其 id 可通过 Discover Category API 获取。

使用 category filter search 时,开发者需要先创建一个 CategoryFilter 对象并加入一个或多个 category id;将该对象设置到 SearchFilters 中,再传入搜索请求。同时需要设置位置点作为搜索的位置上下文。

关键方法

方法 说明
setLocation(double latitude, double longitude) 搜索锚点位置坐标。必填
setFilters(SearchFilters filters) 包含 category filter 的过滤器对象。必填
CategoryFilter.builder().setCategories(List categories) 类目 ID 列表,至少一个。必填
setLimit(Integer limit) 返回结果数量,默认值 10。选填

示例代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
CategoryFilter categoryFilter = CategoryFilter.builder()
    .setCategories(Arrays.asList("241"))
    .build();

SearchFilters searchFilters = SearchFilters.builder()
    .setCategoryFilter(categoryFilter)
    .build();

entityClient.searchRequest()
    .setLocation(37.12419, -121.98828)
    .setFilters(searchFilters)
    .asyncCall(new Callback<EntitySearchResponse>() {

        @Override
        public void onSuccess(EntitySearchResponse response) {
            // 以 JSON 格式打印响应
            LOG.info(EntityJsonConverter.toPrettyJson(response));

            List<Entity> resultEntities = response.getResults();
            for (Entity entity : resultEntities) {
                if (entity.getType() == EntityType.PLACE) {
                    LOG.info("Found Places: {}", entity.getPlace().getName());
                }
            }

        }

        @Override
        public void onFailure(Throwable t) {
            LOG.error("Get unsuccessful response or throwable happened when executing the request.", t);
        }
    });
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
val categoryFilter = CategoryFilter.builder()
    .setCategories(listOf("241"))
    .build()

val searchFilters = SearchFilters.builder()
    .setCategoryFilter(categoryFilter)
    .build()

entityClient.searchRequest()
    .setLocation(37.12419, -121.98828)
    .setFilters(searchFilters)
    .asyncCall(object : Callback<EntitySearchResponse> {

        override fun onSuccess(response: EntitySearchResponse) {
            // 以 JSON 格式打印响应
            Log.i("sdk", EntityJsonConverter.toPrettyJson(response))

            val resultEntities = response.results
            for (entity in resultEntities) {
                if (entity.type == EntityType.PLACE) {
                    Log.i("sdk", "Found Places: ${entity.place.name}")
                }
            }
        }

        override fun onFailure(t: Throwable) {
            Log.e("sdk", "Get unsuccessful response or throwable happened when executing the request.", t)
        }
    })

Brand filter search 用于搜索特定品牌或连锁。调用时开发者需要构建一个品牌 id 列表,并提供一个地理坐标作为搜索的锚点位置。使用品牌搜索后,即使品牌名称存在变体,所有属于该品牌的 POI 都会出现在结果列表中。Telenav 支持数百个常见的消费品牌,覆盖餐饮、咖啡、酒店、餐厅、加油等品类,例如 Starbucks、Chipotle、Subway、Hilton、Best Buy、Nordstrom、Chevron 等。当搜索意图明确为某个品牌时,建议使用 brand search 而不是 onebox search;尤其是品牌名存在变体的情况下,更应使用 brand filter search。

使用该能力时,开发者需要先创建一个 BrandFilter 对象并加入一个或多个品牌 id;再将该对象设置到 SearchFilters 中,最后传入搜索请求。

关键方法

方法 说明
setLocation(double latitude, double longitude) 搜索锚点位置坐标。必填
setFilters(SearchFilters filters) 包含 brand filter 的过滤器对象。必填
BrandFilter.builder().addBrand(String brandId) / setBrands(List brands) 品牌 ID 列表,至少一个。必填
setLimit(Integer limit) 返回结果数量,默认值 10。选填

示例代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
BrandFilter brandFilter = BrandFilter.builder()
    // McDonald's
    .addBrand("99320621")
    .build();

SearchFilters searchFilters = SearchFilters.builder()
    .setBrandFilter(brandFilter)
    .build();

entityClient.searchRequest()
    .setLocation(37.12419, -121.98828)
    .setFilters(searchFilters)
    .asyncCall(new Callback<EntitySearchResponse>() {

        @Override
        public void onSuccess(EntitySearchResponse response) {
            // 以 JSON 格式打印响应
            LOG.info(EntityJsonConverter.toPrettyJson(response));

            List<Entity> resultEntities = response.getResults();
            for (Entity entity : resultEntities) {
                if (entity.getType() == EntityType.PLACE) {
                    LOG.info("Found Places: " + entity.getPlace().getName());
                }
            }
        }

        @Override
        public void onFailure(Throwable t) {
            LOG.error("Brand search failed", t);
        }
    });
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
val brandFilter = BrandFilter.builder()
    // McDonald's
    .addBrand("99320621")
    .build()

val searchFilters = SearchFilters.builder()
    .setBrandFilter(brandFilter)
    .build()

entityClient.searchRequest()
    .setLocation(37.12419, -121.98828)
    .setFilters(searchFilters)
    .asyncCall(object : Callback<EntitySearchResponse> {

        override fun onSuccess(response: EntitySearchResponse) {
            // 以 JSON 格式打印响应
            Log.i("sdk", EntityJsonConverter.toPrettyJson(response))

            val resultEntities = response.results
            for (entity in resultEntities) {
                if (entity.type == EntityType.PLACE) {
                    Log.i("sdk", "Found Places: ${entity.place.name}")
                }
            }
        }

        override fun onFailure(t: Throwable) {
            Log.e("sdk", "Brand search failed", t)
        }
    })

响应示例

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
{
  "code": "SUCCESS",
  "reference_id": "92c30a35-8096-435d-8de2-f0a1e5672d17",
  "search_metadata": {
    "counts": [
      {
        "type": "PLACE",
        "count": 10
      }
    ],
    "query_resolution": {
      "search_location": {
        "latitude": 37.12419,
        "longitude": -121.98828
      }
    }
  },
  "has_more": false,
  "results": [
    {
      "id": "P-YP-cfjuAoaXnJiqkqK5UmGCxw",
      "type": "PLACE",
      "place": {
        "name": "Starbucks",
        "phone_numbers": [
          "18314409801"
        ],
        "categories": [
          {
            "id": "241",
            "name": "Coffee Houses"
          }
        ],
        "address": {
          "formatted_address": "5600 Scotts Valley Dr, Scotts Valley CA 95066, USA",
          "house_number": "5600",
          "street": {
            "body": "Scotts Valley Dr",
            "formatted_name": "Scotts Valley Dr"
          },
          "city": "Scotts Valley",
          "state": "CA",
          "country": "USA",
          "postal_code": "95066",
          "geo_coordinates": {
            "latitude": 37.06147,
            "longitude": -122.00706
          },
          "nav_coordinates": {
            "latitude": 37.06147,
            "longitude": -122.00706
          },
          "address_lines": [
            "5600 Scotts Valley Dr, Scotts Valley CA 95066"
          ]
        },
        "websites": [
          "https://www.starbucks.com"
        ],
        "brands": [
          {
            "brand_id": "5e36d154adf911e299336e1e7d26b4cc"
          }
        ]
      },
      "distance": 7164.0,
      "facets": {
        "open_hours": {
          "regular_open_hours": [
            {
              "day": 7,
              "open_time": [
                {
                  "from": "06:00:00",
                  "to": "18:00:00"
                }
              ]
            },
            {
              "day": 1,
              "open_time": [
                {
                  "from": "05:00:00",
                  "to": "18:00:00"
                }
              ]
            },
            {
              "day": 2,
              "open_time": [
                {
                  "from": "05:00:00",
                  "to": "18:00:00"
                }
              ]
            },
            {
              "day": 3,
              "open_time": [
                {
                  "from": "05:00:00",
                  "to": "18:00:00"
                }
              ]
            },
            {
              "day": 4,
              "open_time": [
                {
                  "from": "05:00:00",
                  "to": "18:00:00"
                }
              ]
            },
            {
              "day": 5,
              "open_time": [
                {
                  "from": "05:00:00",
                  "to": "18:00:00"
                }
              ]
            },
            {
              "day": 6,
              "open_time": [
                {
                  "from": "06:00:00",
                  "to": "18:00:00"
                }
              ]
            }
          ]
        },
        "price_info": {
          "price_level": 1
        },
        "rating": [
          {
            "source": "YELP",
            "average_rating": 3.5,
            "total_count": 50,
            "rating_type": "star",
            "url": "https://www.yelp.com/biz/starbucks-scotts-valley-2"
          }
        ]
      }
    },
    ...
  ],
  "response_time": 102
}

Corridor search 能力允许开发者在驾驶路线两侧叠加一段缓冲带,并将搜索结果限定在该缓冲带范围内。这种能力也叫"沿途搜索(Search Along Route)"。调用时必须再提供关键字、类目过滤或品牌过滤之一,以指明在该走廊内的搜索意图。使用该能力的前提是先获取一条路线——通常通过其它服务返回,形式为 polyline(坐标列表)。开发者再为该路线指定一个缓冲带宽度(单位:米)。为保证性能,路线坐标点数量上限为 200 个。

corridor filter 属于一种 geo-filter,可将搜索限定在指定几何范围内。在 corridor search 场景下,限定几何是带缓冲带的路线坐标列表。构建方式是创建一个 CorridorGeoFilter 对象,并对路线上的每个坐标点循环调用 .addPoint 方法,或通过 setRoute 传入坐标列表。最后将 CorridorGeoFilter 设置到 SearchFilters 中,再传入搜索请求。

关键方法

方法 说明
setLocation(double latitude, double longitude) 用户当前位置,当设置了 geo filter 时代表车辆位置。必填
setQuery(String query) 表明搜索意图的自由文本。
注意:也可以用 brand 或 category filter 代替查询文本
setFilters(SearchFilters filters) 包含 corridor geo filter 的过滤器对象
CorridorGeoFilter.builder().addPoint(double latitude, double longitude) 添加路线上的一个坐标点,最多 200 个点
CorridorGeoFilter.builder().setRoute(List route) 一次性设置路线坐标点列表
CorridorGeoFilter.builder().setRouteWidth(Double routeWidth) 走廊缓冲带宽度(米),默认 1600,最大 2000

示例代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
CorridorGeoFilter geoFilter = CorridorGeoFilter.builder()
    .addPoint(37.763628, -122.47707)
    .addPoint(37.761720, -122.476960)
    .addPoint(37.761711, -122.475670)
    .addPoint(37.761796, -122.473792)
    .addPoint(37.761908, -122.471555)
    .addPoint(37.762061, -122.467285)
    // 可按需追加更多坐标点
    .build();

SearchFilters searchFilters = SearchFilters.builder()
    .setGeoFilter(geoFilter)
    .build();

entityClient.searchRequest()
    .setQuery("food")
    .setLocation(37.763662, -122.47700)
    .setFilters(searchFilters)
    .asyncCall(new Callback<EntitySearchResponse>() {

        @Override
        public void onSuccess(EntitySearchResponse response) {
            // 以 JSON 格式打印响应
            LOG.info(EntityJsonConverter.toPrettyJson(response));

            List<Entity> resultEntities = response.getResults();
            for (Entity entity : resultEntities) {
                // ...
            }
        }

        @Override
        public void onFailure(Throwable t) {
            LOG.error("Corridor search failed", t);
        }
    });
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
val geoFilter = CorridorGeoFilter.builder()
    .addPoint(37.763628, -122.47707)
    .addPoint(37.761720, -122.476960)
    .addPoint(37.761711, -122.475670)
    .addPoint(37.761796, -122.473792)
    .addPoint(37.761908, -122.471555)
    .addPoint(37.762061, -122.467285)
    // 可按需追加更多坐标点
    .build()

val searchFilters = SearchFilters.builder()
    .setGeoFilter(geoFilter)
    .build()

entityClient.searchRequest()
    .setQuery("food")
    .setLocation(37.763662, -122.47700)
    .setFilters(searchFilters)
    .asyncCall(object : Callback<EntitySearchResponse> {

        override fun onSuccess(response: EntitySearchResponse) {
            // 以 JSON 格式打印响应
            Log.i("sdk", EntityJsonConverter.toPrettyJson(response))

            val resultEntities = response.results
            for (entity in resultEntities) {
                // ...
            }
        }

        override fun onFailure(t: Throwable) {
            Log.e("sdk", "Corridor search failed", t)
        }
    })

Polygon search 能力可将搜索结果限定在指定多边形区域的空间范围内。调用时同样必须提供 query、category filter 或 brand filter 之一来指明搜索意图。该多边形可代表任意区域,但建议尺寸控制在合理范围内,使结果能较好地覆盖该区域。常见用法是将搜索限定到一个城市或行政区的边界内。多边形外接矩形对角线长度上限为 300 km。

polygon filter 同样是一种 geo-filter,将搜索限定在多边形几何范围内。构建时创建一个 Polygon 对象,并循环调用 .addPoint 添加坐标点。最少需要 3 个点,多边形会自动连接首尾两点闭合。

关键方法

方法 说明
setLocation(double latitude, double longitude) 用户当前位置。必填
setQuery(String query) 表明搜索意图的自由文本
注意:也可以用 category 或 brand filter 代替查询文本
setFilters(SearchFilters filters) 包含 polygon geo filter 的过滤器对象
Polygon.builder().addPoint(double latitude, double longitude) 添加多边形顶点,至少 3 个点
PolygonGeoFilter.builder(Polygon polygon) 基于 Polygon 构建 polygon geo filter

示例代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
Polygon polygon = Polygon.builder()
    .addPoint(37.12419, -121.98828)
    .addPoint(37.06723, -122.11108)
    .addPoint(36.95373, -122.07400)
    .addPoint(36.98445, -121.82475)
    .addPoint(37.11050, -121.85427)
    .build();

PolygonGeoFilter geoFilter = PolygonGeoFilter
    .builder(polygon)
    .build();

SearchFilters polygonSearchFilters = SearchFilters.builder()
    .setGeoFilter(geoFilter)
    .build();

entityClient.searchRequest()
    .setQuery("Tea")
    .setLocation(37.12419, -121.98828)
    .setFilters(polygonSearchFilters)
    .asyncCall(new Callback<EntitySearchResponse>() {

        @Override
        public void onSuccess(EntitySearchResponse response) {
            // 以 JSON 格式打印响应
            LOG.info(EntityJsonConverter.toPrettyJson(response));

            List<Entity> resultEntities = response.getResults();
            for (Entity entity : resultEntities) {
                if (entity.getType() == EntityType.PLACE) {
                    LOG.info("Found Places: " + entity.getPlace().getName());
                }
            }
        }

        @Override
        public void onFailure(Throwable t) {
            LOG.error("Polygon search failed", t);
        }
    });
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
val polygon = Polygon.builder()
    .addPoint(37.12419, -121.98828)
    .addPoint(37.06723, -122.11108)
    .addPoint(36.95373, -122.07400)
    .addPoint(36.98445, -121.82475)
    .addPoint(37.11050, -121.85427)
    .build()

val geoFilter = PolygonGeoFilter
    .builder(polygon)
    .build()

val polygonSearchFilters = SearchFilters.builder()
    .setGeoFilter(geoFilter)
    .build()

entityClient.searchRequest()
    .setQuery("Tea")
    .setLocation(37.12419, -121.98828)
    .setFilters(polygonSearchFilters)
    .asyncCall(object : Callback<EntitySearchResponse> {

        override fun onSuccess(response: EntitySearchResponse) {
            // 以 JSON 格式打印响应
            Log.i("sdk", EntityJsonConverter.toPrettyJson(response))

            val resultEntities = response.results
            for (entity in resultEntities) {
                if (entity.type == EntityType.PLACE) {
                    Log.i("sdk", "Found Places: ${entity.place.name}")
                }
            }
        }

        override fun onFailure(t: Throwable) {
            Log.e("sdk", "Polygon search failed", t)
        }
    })

Bounding box search 能力可将搜索结果限定在指定矩形区域的空间范围内。调用时同样必须提供 query、category filter 或 brand filter 之一来指明搜索意图。矩形可代表任意区域,但建议尺寸控制在合理范围内,使结果能较好地覆盖该矩形区域。常见用法包括:用户在地图上画出的搜索区域、或将结果限定在当前地图缩放级别或可视范围内。矩形对角线长度上限为 300 km。

bounding box filter 同样是一种 geo-filter,将搜索限定在矩形几何范围内。构建时创建一个 BBox 对象,并传入两个坐标(bottomLeft、topRight)。

关键方法

方法 说明
setLocation(double latitude, double longitude) 用户当前位置。必填
setQuery(String query) 表明搜索意图的自由文本
注意:也可以用 category 或 brand filter 代替查询文本
setFilters(SearchFilters filters) 包含 bounding box geo filter 的过滤器对象
BBox.builder().setBottomLeft(double latitude, double longitude) 矩形左下角坐标
BBox.builder().setTopRight(double latitude, double longitude) 矩形右上角坐标
BBoxGeoFilter.builder(BBox bbox) 基于 BBox 构建 bounding box geo filter

示例代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
BBox bBox = BBox
    .builder()
    .setBottomLeft(37.373974, -122.057767)
    .setTopRight(37.394161, -122.026524)
    .build();

BBoxGeoFilter geoFilter = BBoxGeoFilter
    .builder(bBox)
    .build();

SearchFilters geoSearchFilters = SearchFilters
    .builder()
    .setGeoFilter(geoFilter)
    .build();

entityClient.searchRequest()
    .setQuery("food")
    .setLocation(37.12419, -121.98828)
    .setFilters(geoSearchFilters)
    .asyncCall(new Callback<EntitySearchResponse>() {

        @Override
        public void onSuccess(EntitySearchResponse response) {
            // 以 JSON 格式打印响应
            LOG.info(EntityJsonConverter.toPrettyJson(response));

            List<Entity> resultEntities = response.getResults();

            for (Entity entity : resultEntities) {
                if (entity.getType() == EntityType.PLACE) {
                    LOG.info("Found Places: {}", entity.getPlace().getName());
                }
            }

        }

        @Override
        public void onFailure(Throwable t) {
            LOG.error("BBOX search failed", t);
        }
    });
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
val bBox = BBox
    .builder()
    .setBottomLeft(37.373974, -122.057767)
    .setTopRight(37.394161, -122.026524)
    .build()

val geoFilter = BBoxGeoFilter
    .builder(bBox)
    .build()

val geoSearchFilters = SearchFilters
    .builder()
    .setGeoFilter(geoFilter)
    .build()

entityClient.searchRequest()
    .setQuery("food")
    .setLocation(37.12419, -121.98828)
    .setFilters(geoSearchFilters)
    .asyncCall(object : Callback<EntitySearchResponse> {

        override fun onSuccess(response: EntitySearchResponse) {
            // 以 JSON 格式打印响应
            Log.i("sdk", EntityJsonConverter.toPrettyJson(response))

            val resultEntities = response.results
            for (entity in resultEntities) {
                if (entity.type == EntityType.PLACE) {
                    Log.i("sdk", "Found Places: ${entity.place.name}")
                }
            }
        }

        override fun onFailure(t: Throwable) {
            Log.e("sdk", "BBOX search failed", t)
        }
    })

Reverse Geocoding

逆地理编码(RGC)用于将地理坐标转换为现实世界中的地址。使用 RGC 时返回的 entity 类型只有 address。当应用需要根据给定位置显示一个地址(或城市)时,使用 RGC 非常合适。

要让搜索请求走 RGC 流程,需要将搜索意图设置为 RGC,并提供一个地理坐标作为位置。

关键方法

方法 说明
setLocation(double latitude, double longitude) 待解析为地址的坐标。必填
setAnchor(double latitude, double longitude) 用于 RGC 解析的坐标。若未设置,则使用 location 作为 anchor。选填
setSearchOptions(SearchOptions options) intent 设为 SearchOptions.Intent.REVERSE_GEOCODING 以触发逆地理编码。必填
SearchOptions.builder().setIntent(SearchOptions.Intent intent) 设为 REVERSE_GEOCODING 表示走逆地理编码流程
setLimit(Integer limit) 返回结果数量,默认值 10。选填

示例代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
SearchOptions searchOptions = SearchOptions.builder()
    .setIntent(SearchOptions.Intent.REVERSE_GEOCODING)
    .build();

entityClient.searchRequest()
    .setLocation(37.12419, -121.98828)
    .setSearchOptions(searchOptions)
    .asyncCall(new Callback<EntitySearchResponse>() {

        @Override
        public void onSuccess(EntitySearchResponse response) {
            // 以 JSON 格式打印响应
            LOG.info(EntityJsonConverter.toPrettyJson(response));

            List<Entity> resultEntities = response.getResults();
            for (Entity entity : resultEntities) {
                if (entity.getType() == EntityType.ADDRESS) {
                    LOG.info("Found Address: " + entity.getAddress().getFormattedAddress());
                }
            }
        }

        @Override
        public void onFailure(Throwable t) {
            LOG.error("RGC failed", t);
        }
    });
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
val searchOptions = SearchOptions.builder()
    .setIntent(SearchOptions.Intent.REVERSE_GEOCODING)
    .build()

entityClient.searchRequest()
    .setLocation(37.12419, -121.98828)
    .setSearchOptions(searchOptions)
    .asyncCall(object : Callback<EntitySearchResponse> {

        override fun onSuccess(response: EntitySearchResponse) {
            // 以 JSON 格式打印响应
            Log.i("sdk", EntityJsonConverter.toPrettyJson(response))

            val resultEntities = response.results
            for (entity in resultEntities) {
                if (entity.type == EntityType.ADDRESS) {
                    Log.i("sdk", "Found Address: ${entity.address.formattedAddress}")
                }
            }
        }

        override fun onFailure(t: Throwable) {
            Log.e("sdk", "RGC failed", t)
        }
    })

此外,还有一种特殊的 RGC,支持同时返回指定位置附近的 AddressPlace。触发方式是将 latitude,longitude 作为 query 参数传入,同时把 SearchOptions.intent 设为 AROUND 或保持默认值。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
entityClient.searchRequest()
    .setLocation(37.92021,-122.31476)
    .setQuery("37.92021,-122.31476")
    .asyncCall(new Callback<EntitySearchResponse>() {

        @Override
        public void onSuccess(EntitySearchResponse response) {
            // 以 JSON 格式打印响应
            LOG.info(EntityJsonConverter.toPrettyJson(response));
        }

        @Override
        public void onFailure(Throwable throwable) {

        }
    });
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
entityClient.searchRequest()
    .setLocation(37.92021,-122.31476)
    .setQuery("37.92021,-122.31476")
    .asyncCall(object : Callback<EntitySearchResponse> {

        override fun onSuccess(response: response) {
            for (entity in response.results) {
                // 以 JSON 格式打印响应
                Log.i("sdk", EntityJsonConverter.toPrettyJson(response))
            }
        }

        override fun onFailure(t: Throwable) {

        }
    })

Search 同时支持自由文本和结构化文本查询,适用于语音搜索场景。通常由语音转文字引擎将语音输入转换为文本,转换结果可以带标签后以结构化(tagged)文本发送,也可以不带标签以自由文本发送。Search API 支持带标签的结构化查询。

查询标签(Tag)

标签 说明
WHAT POI 名称、连锁名称或类目标签
WHERE 完整或部分地址,可包含街道和/或城市
CATEGORYID 识别出的类目 ID
ALT_WHAT WHAT 的同音异义词
ALT_WHERE WHERE 的同音异义词
;(分号) 标签分隔符
||(双竖线) 同音词组分隔符

查询语法:tag1=value1;tag2=value2||tag3=value3;tag4=value4;...

查询示例

语音输入 Search Query
Find McDonald's WHAT=McDonald's
Find Restaurant CATEGORYID=226
Find Great America Parkway WHERE=Great America Parkway
Find Restaurant near Great America Parkway CATEGORYID=226;WHERE=Great America Parkway
Find McDonald's near Great America Parkway WHAT=McDonald's;WHERE=Great America Parkway

关键方法

方法 说明
setQuery(String query) 结构化查询字符串,例如 WHAT=McDonald's
setQuery(MultiboxQuery multiboxQuery) 通过 MultiboxQuery.builder().addTag(Tag.WHAT, "McDonald's") 等方式构建结构化查询
setLocation(double latitude, double longitude) 用户当前位置。必填
setSearchOptions(SearchOptions options) trigger 设为 SearchOptions.Trigger.VOICE 表示语音搜索

示例代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// 方式一:直接传入结构化查询字符串
entityClient.searchRequest()
    .setQuery("WHAT=McDonald's")
    .setLocation(37.78509, -122.41988)
    .setSearchOptions(SearchOptions.builder()
        .setTrigger(SearchOptions.Trigger.VOICE)
        .build())
    .setLimit(1)
    .asyncCall(new Callback<EntitySearchResponse>() {

        @Override
        public void onSuccess(EntitySearchResponse response) {
            LOG.info(EntityJsonConverter.toPrettyJson(response));
        }

        @Override
        public void onFailure(Throwable t) {
            LOG.error("Voice search failed", t);
        }
    });

// 方式二:使用 MultiboxQuery 构建带同音词的查询
entityClient.searchRequest()
    .setQuery(MultiboxQuery.builder()
        .addTag(Tag.WHAT, "McDonald's")
        .newGroup()
        .addTag(Tag.ALT_WHAT, "Mac Donalds")
        .build())
    .setLocation(37.78509, -122.41988)
    .setSearchOptions(SearchOptions.builder()
        .setTrigger(SearchOptions.Trigger.VOICE)
        .build())
    .setLimit(1)
    .asyncCall(new Callback<EntitySearchResponse>() {

        @Override
        public void onSuccess(EntitySearchResponse response) {
            LOG.info(EntityJsonConverter.toPrettyJson(response));
        }

        @Override
        public void onFailure(Throwable t) {
            LOG.error("Voice search failed", t);
        }
    });
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
entityClient.searchRequest()
    .setQuery("WHAT=McDonald's")
    .setLocation(37.78509, -122.41988)
    .setSearchOptions(SearchOptions.builder()
        .setTrigger(SearchOptions.Trigger.VOICE)
        .build())
    .setLimit(1)
    .asyncCall(object : Callback<EntitySearchResponse> {

        override fun onSuccess(response: EntitySearchResponse) {
            Log.i("sdk", EntityJsonConverter.toPrettyJson(response))
        }

        override fun onFailure(t: Throwable) {
            Log.e("sdk", "Voice search failed", t)
        }
    })

针对电动车充电站这一类目,SDK 提供了一组专用类,可基于电动车驾驶者关心的关键特征对搜索结果进行过滤;同时还提供了与充电站详情相关的类,如接口类型、接口数量、功率等级、充电网络(品牌)等。

构建相关能力时使用 EVFilter 类。

关键方法

方法 说明
setLocation(double latitude, double longitude) 用户当前位置。必填
setQuery(String query) 搜索关键字,例如 ev station选填
setFilters(SearchFilters filters) 包含 EvFilter 的过滤器对象。选填
EvFilter.builder().setChargerBrands(List brands) 按充电网络(品牌)过滤
EvFilter.builder().setConnectorTypes(List types) 按接口类型过滤
EvFilter.builder().setPowerFeedLevels(List levels) 按功率等级过滤
EvFilter.builder().setCustomerChargeLevels(List levels) 按客户充电等级过滤
EvFilter.builder().setFreeCharge(Boolean freeCharge) true 仅返回免费接口,false 仅返回付费接口,null 返回全部
EvFilter.builder().setAvailable(Boolean available) true 仅返回当前可用接口,否则返回全部
EvFilter.builder().setMinPower / setMaxPower(Double power) 按功率区间(kW)过滤

按充电网络过滤

支持按特定充电网络(如 ChargePoint、EVgo)查找充电站。通过 EvFilter.Builder() 中的 .setChargerBrands 方法设置网络。常见充电网络及其 id 如下:

ID 充电网络
99100001 ChargePoint
99100002 Blink
99100003 eVgo
99100010 ElectrifyAmerica

按接口类型过滤

支持按接口类型(如 J1772、CCS 等)查找充电站。通过 EvFilter.Builder() 中的 .setConnectorTypes 方法设置。常见接口类型示例如下:

ID 接口类型
30001 J1772
30002 SAE Combo
30003 CHAdeMO
30004 Type 2
30005 Type 3
30006 Tesla
30007 NEMA
30008 NEMA 14-50
30009 Plug Type F

按充电等级过滤

支持按功率等级(如 Level 2 或 DC Fast)查找充电站。通过 EvFilter.Builder() 中的 .setPowerFeedLevels 方法设置。当前支持的功率等级如下:

ID 功率等级
1 Level 1
2 Level 2
5 DC Fast
6 Ultra Fast

按客户充电等级过滤

支持按客户充电等级(Customer Charge Level)筛选充电站,在欧洲和澳大利亚常用。通过 EvFilter.builder() 中的 .setCustomerChargeLevels 方法设置。当前支持的等级如下:

ID 客户充电等级
1 普通充电,maxPower ≤ 6kW
2 半快充,6kW < maxPower ≤ 15kW
3 快充,15kW < maxPower ≤ 50kW
4 超快充,maxPower > 50kW

按是否免费过滤

允许用户筛选可免费使用的充电站。该过滤器设为 true 时仅返回免费接口;设为 false 时仅返回付费接口;设为 null 时返回全部接口。

按功率过滤

支持按特定功率区间(KW)筛选充电站。通过 EvFilter.Builder() 中的 .setMinPower.setMaxPower 方法设置。

按可用状态过滤

允许用户筛选当前可用的充电站。该过滤器设为 true 时仅返回当前可用的接口,否则返回全部接口。

示例代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
entityClient.searchRequest()
    .setLocation(37.92021, -122.31476)
    .setQuery("ev station")
    .setFilters(SearchFilters.builder()
            .setEvFilter(EvFilter.builder()
                    .setChargerBrands(Arrays.asList("99100001"))
                    .setConnectorTypes(Arrays.asList("30001", "30002"))
                    .setPowerFeedLevels(Arrays.asList(1, 2))
                    .setFreeCharge(true)
                    .setMinPower(32.0)
                    .setAvailable(true)
                    .build())
            .build())
    .asyncCall(new Callback<EntitySearchResponse>() {

        @Override
        public void onSuccess(EntitySearchResponse response) {
            // 以 JSON 格式打印响应
            LOG.info(EntityJsonConverter.toPrettyJson(response));
        }

        @Override
        public void onFailure(Throwable throwable) {

        }
    });
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
entityClient.searchRequest()
    .setLocation(37.92021, -122.31476)
    .setQuery("ev station")
    .setFilters(SearchFilters.builder()
            .setEvFilter(EvFilter.builder()
                    .setChargerBrands(Arrays.asList("99100001"))
                    .setConnectorTypes(Arrays.asList("30001", "30002"))
                    .setPowerFeedLevels(Arrays.asList(1, 2))
                    .setFreeCharge(true)
                    .setMinPower(32.0)
                    .build())
            .build())
    .asyncCall(object : Callback<EntitySearchResponse> {

        override fun onSuccess(response: response) {
            for (entity in response.results) {
                // 以 JSON 格式打印响应
                Log.i("sdk", EntityJsonConverter.toPrettyJson(response))
            }
        }

        override fun onFailure(t: Throwable) {

        }
    })

EV 功能还支持两种特殊搜索:

排除过滤:指定要排除的 EV 网络。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
entityClient.searchRequest()
    .setLocation(37.92021, -122.31476)
    .setQuery("ev station")
    .setFilters(SearchFilters.builder()
        .setEvFilter(EvFilter.builder()
            .setChargerBrands(Arrays.asList("99100001"), FilterType.EXCLUDE)
            .build())
        .build())
    .asyncCall(new Callback<EntitySearchResponse>() {

        @Override
        public void onSuccess(EntitySearchResponse response) {
            // 以 JSON 格式打印响应
            LOG.info(EntityJsonConverter.toPrettyJson(response));
        }

        @Override
        public void onFailure(Throwable throwable) {

        }
    });
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
entityClient.searchRequest()
    .setLocation(37.92021, -122.31476)
    .setQuery("ev station")
    .setFilters(SearchFilters.builder()
        .setEvFilter(EvFilter.builder()
            .setChargerBrands(Arrays.asList("99100001"), FilterType.EXCLUDE)
            .build())
        .build())
    .asyncCall(object : Callback<EntitySearchResponse> {

        override fun onSuccess(response: response) {
            for (entity in response.results) {
                // 以 JSON 格式打印响应
                Log.i("sdk", EntityJsonConverter.toPrettyJson(response))
            }
        }

        override fun onFailure(t: Throwable) {

        }
    })

按 OCPI location ID 搜索:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
entityClient.searchRequest()
    .setLocation(37.92021, -122.31476)
    .setQuery(MultiboxQuery.builder()
        .addTag(Tag.OCPI_LOCATION_ID, "USCPIL9813")
        .build())
    .asyncCall(new Callback<EntitySearchResponse>() {

        @Override
        public void onSuccess(EntitySearchResponse response) {
            // 以 JSON 格式打印响应
            LOG.info(EntityJsonConverter.toPrettyJson(response));
        }

        @Override
        public void onFailure(Throwable throwable) {

        }
    });

// 或者
entityClient.searchRequest()
    .setLocation(37.92021, -122.31476)
    .setQuery("OCPI_LOCATION_ID=USCPIL9813")
    .asyncCall(new Callback<EntitySearchResponse>() {

        @Override
        public void onSuccess(EntitySearchResponse response) {
            // 以 JSON 格式打印响应
            LOG.info(EntityJsonConverter.toPrettyJson(response));
        }

        @Override
        public void onFailure(Throwable throwable) {

        }
    });
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
entityClient.searchRequest()
    .setLocation(37.92021, -122.31476)
    .setQuery(MultiboxQuery.builder()
        .addTag(Tag.OCPI_LOCATION_ID, "USCPIL9813")
        .build())
    .asyncCall(object : Callback<EntitySearchResponse> {

        override fun onSuccess(response: response) {
            for (entity in response.results) {
                // 以 JSON 格式打印响应
                Log.i("sdk", EntityJsonConverter.toPrettyJson(response))
            }
        }

        override fun onFailure(t: Throwable) {

        }
    })

通常情况下,当前车辆位置(CVP)与搜索点是同一个位置。当二者不同时,可以通过 anchor 参数显式指定搜索位置。

  • locationanchor 同时设置时:
    • location 用作当前车辆位置,用于计算驾驶距离和驾驶时间。
    • anchor 用作搜索位置。
  • 当只设置了 location 时:
    • location 同时用作当前车辆位置和搜索位置。

关键方法

方法 说明
setLocation(double latitude, double longitude) 用户当前位置(地理坐标 latitude, longitude,逗号分隔)。例如 location=37.1245,-122.45678。
setAnchor(double latitude, double longitude) 搜索位置(地理坐标 latitude, longitude,逗号分隔)。例如 location=37.1245,-122.45678。
setQuery(String query) 表明搜索意图的自由文本。
注意:也可以用 brand 或 category filter 代替查询文本。


示例代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
entityClient.searchRequest()
    .setQuery("Fast Food")
    .setLocation(37.12419, -121.98828)
    .setAnchor(37.32587,-121.86442)
    .asyncCall(new Callback<EntitySearchResponse>() {

        @Override
        public void onSuccess(EntitySearchResponse response) {
            // 以 JSON 格式打印响应
            LOG.info(EntityJsonConverter.toPrettyJson(response));

            List<Entity> resultEntities = response.getResults();
            if (resultEntities == null || resultEntities.isEmpty()) {
                LOG.info("No result found");
                return;
            }
            for (Entity entity : resultEntities) {
                if (entity.getType() == EntityType.ADDRESS) {
                    LOG.info("Found Address: " + entity.getAddress().getFormattedAddress());
                } else if (entity.getType() == EntityType.PLACE) {
                    LOG.info("Found Place: " + entity.getPlace().getName());
                }
            }
        }

        @Override
        public void onFailure(Throwable t) {
            LOG.error("Get unsuccessful response or throwable happened when executing the request.", t);
        }
    });
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
entityClient.searchRequest()
    .setQuery("Fast Food")
    .setLocation(37.12419, -121.98828)
    .setAnchor(37.32587,-121.86442)
    .asyncCall(object : Callback<EntitySearchResponse> {

        override fun onSuccess(response: EntitySearchResponse) {
            // 以 JSON 格式打印响应
            Log.i("sdk", EntityJsonConverter.toPrettyJson(response))

            val resultEntities = response.results
            if (resultEntities == null || resultEntities.isEmpty()) {
                Log.i("sdk", "No result found")
                return
            }
            for (entity in resultEntities) {
                if (entity.type == EntityType.ADDRESS) {
                    Log.i("sdk", "Found Address: ${entity.address.formattedAddress}")
                } else if (entity.type == EntityType.PLACE) {
                    Log.i("sdk", "Found Place: ${entity.place.name}")
                }
            }
        }

        override fun onFailure(t: Throwable) {
            Log.e("sdk", "Get unsuccessful response or throwable happened when executing the request.", t)
        }
    })

用于在指定位置附近,针对一个或多个 出口点 / 休息区(ExitPoint),查询指定 品类(Category) 的 POI 可用情况。典型场景:导航中沿路线查询前方出口附近是否有加油站、餐厅、充电桩等。

关键方法

方法 说明
setLocation(double latitude, double longitude) 用户当前位置坐标。必填
setCategories(List categories) / addCategory(String category) 期望在出口附近找到的品类 ID 或别名,可通过 getCategoriesRequest() 获取。必填
setExits(List exits) / addExit(ExitPoint exit) 需要搜索的出口点列表,每个出口点会分别搜索所有品类并返回。必填
setRadiusInMeter(double radiusInMeter) 搜索半径(米),仅对 EXIT_POINT 类型生效,默认 1000。若设置值 < 10 米或 > 5100 米,将回退到默认 1 km。选填
setLocale(Locale locale) 响应内容的语言偏好。选填

ExitPoint 参数

方法 说明
ExitPoint.builder().setLocation(double latitude, double longitude) 出口位置坐标。必填
ExitPoint.builder().setType(ExitType type) 出口类型:EXIT_POINTREST_AREA选填


示例代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
entityClient.searchByExitRequest()
            .setLocation(52.96285, 9.90015)
            .addCategory("2040")
            .addExit(ExitPoint.builder()
                    .setLocation(52.96285, 9.90015)
                    .setType(ExitType.EXIT_POINT)
                    .build())
            .asyncCall(Executors.newSingleThreadExecutor(), new Callback<EntitySearchByExitResponse>() {
                @Override
                public void onSuccess(EntitySearchByExitResponse response) {
                    System.out.println(EntityJsonConverter.toPrettyJson(response));
                }
                @Override
                public void onFailure(Throwable t) {
                    t.printStackTrace();
                }
            });
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
entityClient.searchByExitRequest()
    .setLocation(52.96285, 9.90015)
    .addCategory("2040")
    .addExit(
        ExitPoint.builder()
            .setLocation(52.96285, 9.90015)
            .setType(ExitType.EXIT_POINT)
            .build()
    )
    .asyncCall(Executors.newSingleThreadExecutor(), object : Callback<EntitySearchByExitResponse> {
        override fun onSuccess(response: EntitySearchByExitResponse) {
            println(EntityJsonConverter.toPrettyJson(response))
        }
        override fun onFailure(t: Throwable) {
            t.printStackTrace()

        }
    })

响应参数

EntitySearchResponse 包含以下字段:

方法 / 字段 说明
getStatus() / getCode() 请求状态
getResponseTime() 响应时间(毫秒)
getReferenceId() 响应关联的 reference id
isHasMore() / getHasMore() 是否还有更多结果。为 true 时可发起后续请求获取更多数据
getSearchMetadata() 描述返回结果的元数据,包含结果计数、查询解析信息等
getPaginationContext() 分页上下文,包含上一页/下一页的便捷链接
getResults() 匹配搜索条件的 entity 结果列表

Exit Search 响应

EntitySearchByExitResponse 包含以下字段:

方法 / 字段 说明
getStatus() / getCode() 请求状态
getResponseTime() 响应时间(毫秒)
getReferenceId() 响应关联的 reference id
getResults() 匹配搜索条件的 EntityExit 结果列表。每个结果包含出口位置、可用品类及关联 entity 等信息

状态码

状态码 消息 说明
12200 SUCCESS 请求成功,未发生错误
12400 INVALID_REQUEST 缺少必填参数,或参数值无法解析
12500 INTERNAL_SERVER_ERROR API 服务端内部错误