百度地图多维检索:自然语言理解的深度搜索实践

目录

前言

一、多维检索是什么

1、场景畅想

2、针对的痛点

二、多维检索参数介绍

1、API地址介绍

2、请求参数介绍

3、响应参数介绍

三、Java接口集成

1、UniHttp接口定义

2、GSON对象反序列化

3、集成调用

四、集成遇到的问题

1、召回设置

2、gson泛型序列化实践

3、多页数据获取

五、总结


前言

在当今数字化时代,地图服务已成为人们日常生活中不可或缺的一部分。它不仅帮助我们规划出行路线,还为我们提供了丰富的地理信息和周边服务。然而,随着用户需求的日益复杂化和多样化,传统的地图检索方式已逐渐无法满足人们的需求。用户希望能够以更加自然、便捷的方式与地图进行交互,获取他们想要的信息。正是在这样的背景下,百度地图开启了多维检索与自然语言理解相结合的深度实践之旅,致力于为用户提供更加智能、高效的地图服务体验。

自然语言理解(NLU)作为人工智能领域的一个重要分支,其目标是让计算机能够理解人类的语言。百度地图的多维检索深度实践,正是基于这一前沿技术,试图突破传统地图检索的局限。在传统的地图检索中,用户往往需要输入精确的关键词,如地点名称、地址等,才能获取到相关的地图信息。这种方式虽然在一定程度上能够满足用户的基本需求,但在面对复杂的查询需求时,就显得力不从心了。例如,用户可能想查询"附近评分最高的餐厅",或者"第一次来适合亲子的旅游景点",这些复杂的查询需求往往难以通过简单的关键词输入来实现。

在深度实践的过程中,自然语言的复杂性和多样性使得理解用户的意图并非易事。不同的用户可能会用不同的表达方式来描述同一个需求,这就要求百度地图的自然语言理解系统能够具备强大的语义理解能力。支持自然语言进行检索应该是一个非常大的亮点。因此,为了保证检索结果的准确性和及时性,百度地图还需要不断优化其算法和数据更新机制。尽管面临诸多挑战,百度地图的多维检索深度实践已经取得了显著的成果。通过不断优化自然语言理解算法,百度地图能够更准确地理解用户的查询意图。

本文将详细介绍百度地图的多维检索深度服务,文章将详细介绍百度地图的服务内容,同时以Java语言为例,详细介绍如何集成多维检索,最后将分享在集成过程中常见的一些问题以及解决方案。这不仅是一次技术创新的尝试,更是一次对用户体验的深刻洞察。它标志着地图服务从传统的关键词检索向更加智能化、人性化的自然语言交互转变。未来,随着自然语言理解技术的不断发展和持续优化,我们相信,百度地图将为用户提供更加智能、便捷、高效的地图服务体验。这不仅将改变人们使用地图的方式,也将推动整个地图服务行业向更加智能化的方向发展。

一、多维检索是什么

在详细介绍多维检索服务前,我们首先来对多维检索服务的使用场景、能解决什么痛点等进行详细介绍。通过本节的内容介绍,让大家对多维检索服务有一个更详细的认识。

1、场景畅想

场景一:晚上和朋友约饭,朋友带着小狗;用户一条消息:"附近能带狗的餐厅"。传统的地点检索会返回一串"餐厅"------但它不知道"能带狗"这种限制是否被满足。结果是用户还得筛选、再筛选,体验糟糕。

场景二:周末带着小朋友去踏青防风,由于是第一次去该地,准备搜索"第一次来适合亲子的旅游景点"。相信旅游景点可以返回很多信息的,但是可能返回了很多的干扰项,比如适合情侣、适合老年人,对亲子是不太友好的,吸引力也不足。常规的检索需要分步骤,如果检索接口中有平分数据,再进行综合评价后在返回。

在此背景之下,多维检索就是为这种"带额外条件的自然语言检索"而生的。

2、针对的痛点

  • 把"意图 + 限制"一次性理解并检索(比如:宠物友好、适合带娃、30人以内包场)。

  • 降低客户端复杂过滤逻辑(减少前端和后端的条件拼接)。

  • 更好地把自然语言转为结构化条件(利于做个性化推荐)。

这里的多维不是指多个搜索条件,比如增加评价过滤,增加距离过滤等。而是增加了一个智慧的维度,支持自然语言的理解。使用多维检索,不仅可以理解你的需要是旅游景点(餐厅),而且还能读懂你的附加限制,适合亲子(或带宠物)等等。通过自然语言,让检索更加智能。总而言之,多维检索 = 会读"附加条件"的搜索。用户的自然语言不仅被当成"类目",同时被解析出多种维度(属性、标签、限制、意图),并据此返回更精准的候选结果。

二、多维检索参数介绍

多维检索服务有了基本的认识之后,下面我们将对百度地图的多维检索服务进行详细介绍,主要包含多维检索服务的请求地址、请求参数和响应参数内容进行介绍。从这里开始是详细的技术内容介绍,是后续接口请求及对象转换的基础。

1、API地址介绍

bash 复制代码
http://api.map.baidu.com/api_place_pro/v1/region?page_num=0&region_limit=true&scope=2&output=json&extensions_adcode=true&region=长沙&ak=您的ak&query=第一次来适合亲子的旅游景点

2、请求参数介绍

参数名称 参数含义 示例 必选
query 检索关键字 宠物友好餐厅
region 限定搜索区域 北京市
region_limit 区域数据召回限制,为true时,仅召回region对应区域内数据 true/false
type 对query召回结果进行二次筛选,type内容建议参考POI分类内容,建议query同属于一个大类; 如query=美食 type=火锅(用于泛搜索场景) query和type支持只填一项 火锅
scope 检索结果详细程度。取值为1 或空,则返回基本信息;取值为2,返回检索POI详细信息 1、 2
coord_type 传入的坐标类型,1(wgs84ll即GPS经纬度),2(gcj02ll即国测局经纬度坐标),3(bd09ll即百度经纬度坐标),4(bd09mc即百度米制坐标) 1、2、3(默认)、 4
center 传入poi坐标,辅助检索结果按距离排序与返回 需要搭配排序字段一起使用并结合coord_type字段说明该字段的坐标类型 38.76623,116.43213 lat<纬度>,lng<经度>
filter 检索排序条件,包含以下3部分 industry_type:排序支持的行业类型,取值有:hotel(酒店宾馆);cater(餐饮);life(生活类) sort_name:排序方式,取值有:default(默认);price(价格);overall_rating(评分);distance(距离排序,需结合center字段一起使用) sort_rule:排序规则,取值有:0(从高到低),1(从低到高) industry_type:cater sort_name:overall_rating sort_rule:1
extensions_adcode 是否召回国标行政区划编码、true(召回)、false(不召回) true、false
address_result query传入结构化地址(如:上地十街10号),检索结果返回数据的类型。若不传入该字段,默认召回门址数据,仅当address_result=false时,召回相应的POI数据 false
photo_show 是否输出图片信息:true(输出),false(不输出) 购买商用授权后可联系商务,提交工单申请开通 false, true 默认值: false
language 多语言检索,支持多种语言召回结果,参考语种列表,默认为中文。 注意:该功能为高级付费功能,您可提交工单咨询。 en
page_num 分页页码,默认为0,0代表第一页,1代表第二页,以此类推。常与page_size搭配使用,仅当返回结果为poi时可以翻页。 0、1、2
page_size 单次召回POI数量,默认为10条记录,最大返回20条。取值为10-20 10
ret_coordtype 返回的坐标类型,可选参数,默认返回百度坐标系坐标详细说明 bd09ll、bd09mc、wgs84ll、gcj02ll
output 输出数据格式 json/xml
baidu_user_id 用户请求id,任意定义,不可超过16位字符串 输入baidu_user_id和baidu_session_id参数后,检索接口会自动关联历史搜索行为,使返回结果逐步个性化------越用越精准,成为"私人定制版搜索接口" 12345
baidu_session_id 百度对话id,任意定义,不可超过16位字符串 用于辨别同一轮请求,如请求该接口效果不满意,请继续使用相同的ssesion_id发起请求,后续将对第一轮的请求进行效果优化, 若对效果满意并需更多字段则可以使用相同session_id请求地点详情接口 注:与baidu_user_id配合使用,但不可和baidu_user_id相同 67891

3、响应参数介绍

返回参数 类型 备注
status int 本次API访问状态,如果成功返回0,如果失败返回其他数字。(见服务状态码)
message string 对API访问状态值的英文说明,如果成功返回ok,并返回结果字段,如果失败返回错误说明。
total int 召回poi数量,开发者请求中设置了page_num字段才会出现total字段。出于数据保护目的,单次请求total最多为150。
result_type string 召回结果类型:region_type 行政区划类型;address_type 结构化地址类型;poi_type poi类型;city_type 城市类型
query_type string 搜索类型:精搜precise/泛搜general
results object 返回的结果
uid string poi的唯一标示,ID
name string poi名称,单次请求最多返回10条结果
location object poi经纬度坐标
lat float 纬度值
lng float 经度值
province string poi所属省份
city string poi所属城市
area string poi所属区县
town string poi所属乡镇街道
town_code int poi所属乡镇街道编码
adcode int poi所属区域代码
address string poi所在地址
matched_terms string 多维检索匹配标签
poi_related_score string poi匹配置信度 1.8以上为非常满足,1.5分以上为比较满足,0.8-1.5是一般满足,0.8以下不满足
status string poi营业状态 : 空(代表正常营业) 推算位置(代表开放/营业/办公状态可能有变化) 暂停营业 可能已关闭 已关闭 购买商用授权后可联系商务,提交工单申请开通
telephone string poi的电话
detail string 是否有详情页:1有,0没有
detail_info object 详细信息
classified_poi_tag string POI展示分类(细致分类)

请注意,在响应参数这里,尤其是detail_info这里,经过实测,由于后台接口返回参数列表与文有一定差异,大家在定义实例类时一定要注意。关于详细信息,在后文中给出实例。

三、Java接口集成

本节将以Java语言为例,重点讲解如何使用Java来集成百度地图的多维检索接口。接口访问框架我们使用UniHttp来进行实现,为了方便我们对后续的对象进行处理,需要将接口返回的json数据反序列化为JavaBean,最后给出详细的调用实例,并展示调用成果。

1、UniHttp接口定义

关于如何使用UniHttp来访问api接口,在博主的系列博文中有过详细的介绍。这里不进行赘述。在前面的请求接口中,我们列出了详细的参数,这里我们根据实际情况选取一下参数进行检索查询:

参数名称 参数含义 示例 必选
query 检索关键字 宠物友好餐厅
region 限定搜索区域 北京市
scope 检索结果详细程度。取值为1 或空,则返回基本信息;取值为2,返回检索POI详细信息 1、 2
coord_type 传入的坐标类型,1(wgs84ll即GPS经纬度),2(gcj02ll即国测局经纬度坐标),3(bd09ll即百度经纬度坐标),4(bd09mc即百度米制坐标) 1、2、3(默认)、 4
extensions_adcode 是否召回国标行政区划编码、true(召回)、false(不召回) true、false
page_num 分页页码,默认为0,0代表第一页,1代表第二页,以此类推。常与page_size搭配使用,仅当返回结果为poi时可以翻页。 0、1、2
page_size 单次召回POI数量,默认为10条记录,最大返回20条。取值为10-20 10
ret_coordtype 返回的坐标类型,可选参数,默认返回百度坐标系坐标详细说明 bd09ll、bd09mc、wgs84ll、gcj02ll
output 输出数据格式 json/xml
baidu_user_id 用户请求id,任意定义,不可超过16位字符串 输入baidu_user_id和baidu_session_id参数后,检索接口会自动关联历史搜索行为,使返回结果逐步个性化------越用越精准,成为"私人定制版搜索接口" 12345
baidu_session_id 百度对话id,任意定义,不可超过16位字符串 用于辨别同一轮请求,如请求该接口效果不满意,请继续使用相同的ssesion_id发起请求,后续将对第一轮的请求进行效果优化, 若对效果满意并需更多字段则可以使用相同session_id请求地点详情接口 注:与baidu_user_id配合使用,但不可和baidu_user_id相同 67891

后面两个参数是两个新的参数,与之前的其它的接口都有所不同,主要用于标记请求和分辨是否同一请求,关于这两个参数的作用,后面再进行介绍。使用UniHttp定义请求的核心方法如下:

java 复制代码
package com.yelang.project.thridinterface;
import com.burukeyou.uniapi.http.annotation.HttpApi;
import com.burukeyou.uniapi.http.annotation.param.QueryPar;
import com.burukeyou.uniapi.http.annotation.request.GetHttpInterface;
import com.burukeyou.uniapi.http.core.response.HttpResponse;
/**
 * -支持 用户自然语言查询的多定语多维度检索服务
 * @author 夜郎king
 */
@HttpApi(url = "http://api.map.baidu.com/api_place_pro/v1")
public interface BaiduApiPlaceProService {

	/**
	 * - 多维检索服务接口,提供对用户自然语言查询的多定语多维度检索,支持模糊匹配和语义理解,例"可以带狗的餐厅" "适合自驾的旅游景点"类的复杂泛搜。
	 * @param query 检索关键字
	 * @param region 限定搜索区域
	 * @param scope 检索结果详细程度。取值为1 或空,则返回基本信息;取值为2,返回检索POI详细信息
	 * @param extensions_adcode 是否召回国标行政区划编码、true(召回)、false(不召回)
	 * @param page_num 分页页码,默认为0,0代表第一页,1代表第二页,以此类推。常与page_size搭配使用,仅当返回结果为poi时可以翻页。
	 * @param page_size 单次召回POI数量,默认为10条记录,最大返回20条。取值为10-20
	 * @param ret_coordtype 返回的坐标类型,可选参数,默认返回百度坐标系
	 * @param baidu_user_id 用户请求id,任意定义,不可超过16位字符串
							输入baidu_user_id和baidu_session_id参数后,检索接口会自动关联历史搜索行为,
							使返回结果逐步个性化------越用越精准,成为"私人定制版搜索接口"
	 * @param baidu_session_id 百度对话id,任意定义,不可超过16位字符串
							用于辨别同一轮请求,如请求该接口效果不满意,请继续使用相同的ssesion_id发起请求
							后续将对第一轮的请求进行效果优化, 
							若对效果满意并需更多字段则可以使用相同session_id请求地点详情接口
							注:与baidu_user_id配合使用,但不可和baidu_user_id相同
	 * @param output 输出数据格式
	 * @param ak 用户的ak值
	 * @return
	 */
	@GetHttpInterface("/region")
	public HttpResponse<String> search(@QueryPar("query") String query, @QueryPar("region") String region,
			@QueryPar("scope") int scope,@QueryPar("extensions_adcode") boolean extensions_adcode,@QueryPar("page_num") int page_num,
			@QueryPar("page_size") int page_size,@QueryPar("ret_coordtype") String ret_coordtype,
			@QueryPar("baidu_user_id") String baidu_user_id, @QueryPar("baidu_session_id") String baidu_session_id,
			@QueryPar("output") String output, @QueryPar("ak") String ak);
}

2、GSON对象反序列化

为了实现最大化实现Java对象的转化,我们需要将响应参数进行拆分,然后按照响应参数的结构进行重构。这里为了展示实际调用的情况,先给大家看一下detail_info的详情部分,这个部分也是跟官网稍微有一点出入的部分,见下图:

这里我们将响应对象封装成以下表所示:

|----|---------------------------------|-------------------------------------------|
| 序号 | 类名 | 描述 |
| 1 | BdCommonDTO.java | 百度接口公共DTO对象,用于封装通用信息 |
| 2 | BdSearchRespDTO.java | 百度搜索相应公共对象,不仅可以用于3.0的接口检索,也可以基于2.0的接口检索封装 |
| 3 | BdLocationDTO.java | 百度位置对象,只封装包含经纬度位置的对象 |
| 4 | BdApiPlaceProBasicInfoDTO.java | 多维检索基本信息DTO对象 |
| 5 | BdApiPlaceProDetailInfoDTO.java | 多维检索详情信息DTO对象 |

BdCommonDTO.java是百度接口的公共定义,是大多数接口的公共父类,仅定义了状态和消息等属性,代码如下:

java 复制代码
package com.yelang.project.meteorology.domain;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
/**
 * - 百度接口公共DTO对象,用于封装通用信息
 * @author 夜郎king
 */
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString
public class BdCommonDTO implements Serializable {
	private static final long serialVersionUID = 4985268844473756688L;
	private int status;//状态码 本次API访问状态,如果成功返回0,如果失败返回其他数字。
	private String message;//响应信息 对status的中文描述
}

BdSearchRespDTO.java作为搜索接口的通用父类,为了保证能兼容不同的搜索基本信息,这里我们需要使用泛型来进行类的定义,定义如下:

java 复制代码
package com.yelang.project.meteorology.domain.baidudto;
import java.io.Serializable;
import java.util.List;
import com.google.gson.annotations.SerializedName;
import com.yelang.project.meteorology.domain.BdCommonDTO;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
/**
 * - 百度搜索相应公共对象
 * @author Administrator
 */
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString(callSuper=true)//callSuper=true表示输出父类属性
@EqualsAndHashCode(callSuper=true)
public class BdSearchRespDTO<T> extends BdCommonDTO implements Serializable{
	private static final long serialVersionUID = 4478675842144206687L;
	private int total;//召回poi数量,开发者请求中设置了page_num字段才会出现total字段。出于数据保护目的,单次请求total最多为150。
	@SerializedName("result_type")
	private String resultType;//召回结果类型:region_type 行政区划类型;address_type 结构化地址类型;poi_type poi类型;city_type 城市类型
	@SerializedName("query_type")
	private String queryType;//搜索类型:精搜precise/泛搜general
	private List<T> results;//返回的结果
}

BdLocationDTO.java主要是为了封装位置信息,其实就是经纬度坐标,类比较简单,核心代码如下:

java 复制代码
package com.yelang.project.meteorology.domain.baidudto;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
/**
 * -百度位置对象,只封装包含经纬度位置的对象
 * @author 夜郎king
 */
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString
public class BdLocationDTO implements Serializable{
	private static final long serialVersionUID = 5465938480868148043L;
	private float lat;//纬度值
	private float lng;//经度值
}

BdApiPlaceProBasicInfoDTO.java作为多维检索响应参数的基本信息对象,主要封装了其对应的基本信息属性,核心代码如下:

java 复制代码
package com.yelang.project.meteorology.domain.baidudto;
import java.io.Serializable;
import com.google.gson.annotations.SerializedName;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
/**
 * - 多维检索基本信息DTO对象
 * @author 夜郎king
 */
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString
public class BdApiPlaceProBasicInfoDTO implements Serializable {
	private static final long serialVersionUID = 4939274490561797138L;
	private String uid;// poi的唯一标示,ID
	private String name;// poi名称
	private BdLocationDTO location;// poi经纬度坐标
	private String province;// poi所属省份
	private String city;// poi所属城市
	private String area;// poi所属区县
	private String town;// poi所属乡镇街道
	@SerializedName("town_code")
	private String townCode;// poi所属乡镇街道编码
	private String adcode;//poi所属区域代码 ,设置召回后有值
	// adcode int poi所属区域代码 多维检索接口没有返回
	private String address;// poi所在地址
	@SerializedName("match_term") 
	private String matchTerm;// 多维检索匹配标签
	@SerializedName("poi_related_score")
	private String poiRelatedScore;// poi匹配置信度 1.8以上为非常满足,1.5分以上为比较满足,0.8-1.5是一般满足,0.8以下不满足
	private String status;// poi营业状态 :空(代表正常营业)推算位置(代表开放/营业/办公状态可能有变化)暂停营业可能已关闭已关闭购买商用授权后可联系商务,提交工单申请开通
	private String telephone;// poi的电话
	private String detail;// 是否有详情页:1有,0没有
	@SerializedName("street_id")
	private String streetId;
	@SerializedName("detail_info")
	private BdApiPlaceProDetailInfoDTO detailInfo;// 详细信息
}

BdApiPlaceProDetailInfoDTO.java是详情信息,这里贴出通过接口实际请求后的响应参数,具体如下:

bash 复制代码
"detail_info": {
    "classified_poi_tag": "旅游景点;水族馆;海洋馆",
	"tag": "旅游景点;水族馆",
	"navi_location": {
	    "lat": 28.20450810319875,
		"lng": 112.86519398953753
	},
	"type": "scope",
	"detail_url": "http://api.map.baidu.com/place/detail?uid=2680b6552aaa5d830482c27f&output=html&source=placeapi_v3",
	"overall_rating": "4.5",
	"comment_num": "200",
	"shop_hours": "10:00-18:00",
	"label": "景区,",
	"children": [],
	"parent_id": "c43f26e63257ad67246e987d",
	"ranking": "长沙亲子景点口碑榜No.22",
	"d7_hot_value": 41,
	"heat_trend": "近7天热度增长33%",
	"view_heat": 457.2,
	"arrival_heat": 57.35,
	"interact_heat": 1.05
}

转换成JavaBean定义如下:

java 复制代码
package com.yelang.project.meteorology.domain.baidudto;
import java.io.Serializable;
import java.util.List;
import com.google.gson.annotations.SerializedName;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
/**
 * - 多维检索信息详情DTO
 * @author 夜郎king
 */
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString
public class BdApiPlaceProDetailInfoDTO implements Serializable{
	private static final long serialVersionUID = -7222313367171531325L;
	@SerializedName("classified_poi_tag")
	private String classifiedPoiTag;//POI展示分类(细致分类);
	@SerializedName("new_alias")
	private String newAlias;//poi别名
	private String tag;//标签
	@SerializedName("navi_location")
	private BdLocationDTO naviLocation;//导航位置
	private String type;//"type": "scope",
	@SerializedName("detail_url")
	private String detailUrl;//POI 详情页
	@SerializedName("overall_rating")
	private float overallRating;//poi的综合评分
	@SerializedName("image_num")
	private int imageNum;
	@SerializedName("comment_num")
	private int commentNum;//poi的评论数
	@SerializedName("shop_hours")
	private String shopHours;//poi的营业时间,10:30-14:00,16:30-22:00"shop_hours": "09:00-21:00",
	private String label;//poi权威标签,标签细分解释,比如停车场标签(地上停车场/地下停车场),知名景区标签(几A级景区),酒店标签(什么类型酒店)等
	private List<BdApiPlaceProDetailInfoDTO> children;//poi子点
	@SerializedName("parent_id")
	private String parentId;
	private String ranking;//poi的相关榜单排名
	@SerializedName("d7_hot_value")
	private float d7HotValue;//一周热度值 "d7_hot_value": 55,
	@SerializedName("heat_trend")
	private String heatTrend;//
	@SerializedName("view_heat")
	private float viewHeat;//查看热度
	@SerializedName("arrival_heat")
	private float arrivalHeat;//到达热度
	@SerializedName("interact_heat")
	private float interactHeat;//互动热度
}

3、集成调用

经过上述的对象映射定义之后,接下来我们就可以进行接口的实际调用,看看接口的实际返回。集成调用的核心代码如下:

java 复制代码
package com.yelang.project.unihttp;
import java.lang.reflect.Type;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import com.burukeyou.uniapi.http.core.response.HttpResponse;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.yelang.common.utils.StringUtils;
import com.yelang.project.meteorology.domain.baidudto.BdApiPlaceProBasicInfoDTO;
import com.yelang.project.meteorology.domain.baidudto.BdSearchRespDTO;
import com.yelang.project.thridinterface.BaiduApiPlaceProService;
@SpringBootTest
@RunWith(SpringRunner.class)
public class BaiduApiPlaceProServiceCase {
	/**
	 *- 百度地图ak值
	 */
	private static final String BAIDU_CLIENT_AK = "baidu_ak";
	@Autowired
	private BaiduApiPlaceProService apiPlaceProService;
	@SuppressWarnings({"serial" })
	@Test
	public void nlpSearch() {
		String query = "第一次来适合亲子的旅游景点";
		String region = "158";//158,长沙市
		int scope = 2;//检索结果详细程度。取值为1 或空,则返回基本信息;取值为2,返回检索POI详细信息
		boolean extensions_adcode = true;//不召回adcode
		int page_num =0;
		int page_size = 20;
		String ret_coordtype = "wgs84ll";
		String baidu_user_id = "12345";
		String baidu_session_id = "67891";
		String output = "json";
		String ak = BAIDU_CLIENT_AK;
		HttpResponse<String> result = apiPlaceProService.search(query, region, scope,extensions_adcode,page_num,page_size, ret_coordtype, baidu_user_id, baidu_session_id, output, ak);
		Gson gson = new Gson();
		if(StringUtils.isNotEmpty(result.getBodyResult())) {
			System.out.println(result.getBodyToString());
			BdSearchRespDTO<BdApiPlaceProBasicInfoDTO> bdSearchRespDTO = gson.fromJson(result.getBodyResult(), BdSearchRespDTO.class);
			System.out.println(bdSearchRespDTO.getTotal());
			System.out.println(bdSearchRespDTO);
			List<BdApiPlaceProBasicInfoDTO> results = bdSearchRespDTO.getResults();
			for(BdApiPlaceProBasicInfoDTO basicInfo : results) {
				System.out.println(basicInfo);
				System.out.println(basicInfo.getMatchTerm());
				System.out.println(basicInfo.getAdcode());
				System.out.println(basicInfo.getTownCode());
			}
		}
	}
}

以上就是简单的一个案例集成,基本调用方法和思路都是没有问题,代码编译也没有问题,那么是否程序是否能正常运行呢?答案是不行。下面来看看在集成过程中可能会碰到什么问题,以及如何解决。这里展示一次成功的结果,说明多维检索的服务请求响应:

从检索结果来看,这个检索后台真的很懂你啊,不仅按照预期来进行推荐,同时还直接给出的匹配规则,具体如下:

bash 复制代码
name=九悦湘·湘菜·家宴(东塘店), address=劳动中路新东塘商业广场2楼, matchTerm=家庭聚餐;网红餐饮;停车位充足, poiRelatedScore=1.7929307222366333, ranking=null, d7HotValue=1.0, heatTrend=近7天热度增长19%, viewHeat=15.0, arrivalHeat=5.6, interactHeat=0.25))

name=一席餐厅(长沙总部基地店), address=万家丽南路二段688号中南总部基地1-B栋1001房, matchTerm=家庭聚餐;餐厅不错;停车场大, poiRelatedScore=1.161329984664917, ranking=雨花区回头客多的美食榜No.20, d7HotValue=2.0, heatTrend=近7天热度递减4%, viewHeat=18.95, arrivalHeat=6.25, interactHeat=0.25))

name=长沙嘻院(长沙南站店),  address=东山街道黎托社区8组(樱之谷北门东50米), matchTerm=家庭聚餐;湖中餐厅;停车场宽敞, poiRelatedScore=1.595179557800293, ranking=null, d7HotValue=8.0, heatTrend=近7天热度增长0%, viewHeat=76.2, arrivalHeat=18.3, interactHeat=1.7))

name=西湖景里餐厅(西湖公园店),  address=西湖街道西湖公园北门2号停车场内侧, matchTerm=家庭聚餐;湖边餐厅;酥骨鸭好吃, poiRelatedScore=1.8892595767974854, ranking=咸嘉新村最热湘菜榜No.9, d7HotValue=1.0, heatTrend=近7天热度增长3%, viewHeat=13.2, arrivalHeat=3.35, interactHeat=0.1))

name=时间仓(悠游小镇店), address=悠游小镇178号(大塘地铁站4号口步行450米), matchTerm=家庭聚餐;网红餐饮;停车位充足, poiRelatedScore=1.7816898822784424, ranking=圭塘最热湘菜榜No.8, d7HotValue=1.0, heatTrend=近7天热度增长10%, viewHeat=8.65, arrivalHeat=3.25, interactHeat=0.2))

name=七号菜馆(湘江世纪城店), address=凤亭路口10号重建地40栋(金霞安置小区对面), matchTerm=适合家庭聚餐;当家肉;菜品丰富, poiRelatedScore=1.2932199239730835, ranking=开福区最热湘菜榜No.7, d7HotValue=2.0, heatTrend=近7天热度增长3%, viewHeat=21.35, arrivalHeat=7.15, interactHeat=0.2))

name=南景饭店(圭塘河店), address=圭塘河路滨水园岸C栋三楼(双塔国际B座对面), matchTerm=家庭聚餐;老字号餐厅;停车场方便, poiRelatedScore=1.838053822517395, ranking=长沙奢华餐厅美食口碑榜No.9, d7HotValue=2.0, heatTrend=近7天热度递减20%, viewHeat=17.35, arrivalHeat=6.1, interactHeat=0.25))

将匹配的规则对列出来了,明明白白的推荐。

四、集成遇到的问题

下面将简单讲解在服务集成过程当中可能会遇到什么问题,以及如何在碰到这些问题时如何去解决。希望这些问题可以帮助您解决集成的一些基础问题。

1、召回设置

接口中的召回设置其实有多个参数都有涉及,根据重要性,我们选取两个比较重要的召回参数,并且介绍如果不设置可能会有什么影响。首先第一个参数就是page_num,这个参数的设置与相关,total是我们后续用于是否有后续数据的重要判断依据。

adcode的召回,adcode是匹配的地点的行政区划编号召回,这个在需要进行空间分析时,如果需要进行属性关联和过滤,就必须要设置,否则adcode返回null,设置代码如下:

java 复制代码
boolean extensions_adcode = true;//不召回adcode

详情的设置,有的朋友在实践过程中,可能没有设置详情返回,因此得到的json结果中没有详情属性。这也是与我们的召回设置相关,这里我们设置如下:

java 复制代码
int scope = 2;//检索结果详细程度。取值为1 或空,则返回基本信息;取值为2,返回检索POI详细信息

2、gson泛型序列化实践

在前面介绍GSON的对象反序列化时,我们介绍了为了通用性,我们进行了泛型的设计,这种设计思路能更好的进行程序对象多样性的支持。但是在反序列化时又遇到蛮多问题,在使用常规的GSON设置时,比如以下设置代码:

java 复制代码
BdSearchRespDTO<BdApiPlaceProBasicInfoDTO> bdSearchRespDTO = gson.fromJson(result.getBodyResult(), BdSearchRespDTO.class);

使用以上模板设置,一定会遇到以下问题:

报错信息截图提示如下:

bash 复制代码
/*
java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to com.yelang.project.meteorology.domain.baidudto.BdApiPlaceProBasicInfoDTO
at com.yelang.project.unihttp.BaiduApiPlaceProServiceCase.nlpSearch(BaiduApiPlaceProServiceCase.java:53)
*/

这其实也是反序列化的一个大问题,如何支持泛型的数据反序列化。这里给出解决方案,使用Type定义来进行精确准换,代码如下:

java 复制代码
Type type = new TypeToken<BdSearchRespDTO<BdApiPlaceProBasicInfoDTO>>(){}.getType();
BdSearchRespDTO<BdApiPlaceProBasicInfoDTO> bdSearchRespDTO = gson.fromJson(result.getBodyResult(), type);

在此运行程序后控制台展示正常,如下图所示:

3、多页数据获取

这其实是与多条数据的获取为前提的,如果数据的总数超出了每页的获取页面,就一定会使用多页获取的方法,多页获取的方法是主动发起下一页请求,然后通过召回total来进行返回数据的判断,增加的核心代码如下:

java 复制代码
HttpResponse<String> result = null;
// 使用 TypeToken 获取完整类型信息
Type type = new TypeToken<BdSearchRespDTO<BdApiPlaceProBasicInfoDTO>>(){}.getType();
int dataCount = 0;
do {
    System.out.println("抓取第" + (page_num +1 ) + "页");
	result = apiPlaceProService.search(query, region, scope,extensions_adcode,page_num,page_size, ret_coordtype, baidu_user_id, baidu_session_id, output, ak);
	System.out.println(result.getBodyResult());
	if(StringUtils.isNotEmpty(result.getBodyResult())) {
	    BdSearchRespDTO<BdApiPlaceProBasicInfoDTO> bdSearchRespDTO = gson.fromJson(result.getBodyResult(), type);
		System.out.println(bdSearchRespDTO.getTotal());
		System.out.println(bdSearchRespDTO);
		List<BdApiPlaceProBasicInfoDTO> results = bdSearchRespDTO.getResults();
		for(BdApiPlaceProBasicInfoDTO basicInfo : results) {
		    System.out.println(basicInfo);
			System.out.println(basicInfo.getMatchTerm());
			System.out.println(basicInfo.getAdcode());
			System.out.println(basicInfo.getTownCode());
		}
		dataCount = bdSearchRespDTO.getTotal();
		page_num ++;
	}
	Thread.sleep(3000L);//休眠3000秒
} while (dataCount > 0);
System.out.println("一共抓取数据页数:" + (page_num ++ ) );

多轮获取运行如下:

五、总结

以上就是本文的主要内容,本文将详细介绍百度地图的多维检索深度服务,文章将详细介绍百度地图的服务内容,同时以Java语言为例,详细介绍如何集成多维检索,最后将分享在集成过程中常见的一些问题以及解决方案。通过案例的详细讲解,相信大家已经对百度地图的多维检索服务有了很深的认识,同时对其API和Java集成调用有个基本的了解。本文抛砖引玉,相信有更多的朋友基于这个API实现更丰富的应用。

未来,随着自然语言理解技术的不断发展和持续优化,我们相信,百度地图将为用户提供更加智能、便捷、高效的地图服务体验。这不仅将改变人们使用地图的方式,也将推动整个地图服务行业向更加智能化的方向发展。行文仓促,定有许多的不足之处,欢迎各位朋友在评论区批评指正,不胜感激。