文档的查询同样适用 RestHighLevelClient 对象,基本步骤包括:
- 准备 Request 对象
- 准备请求参数
- 发起请求
- 解析响应
快速入门
我们以 match_all 查询为例
发起查询请求
@Testvoid testMatchAll() throws IOException {// 1.准备RequestSearchRequest request = new SearchRequest("hotel");// 2.组织DSL参数request.source().query(QueryBuilders.matchAllQuery());// 3.发送请求,得到响应结果SearchResponse response = client.search(request, RequestOptions.DEFAULT);// ...解析响应结果}
代码解读:
- 第一步,创建
SearchRequest对象,指定索引库名 - 第二步,利用
request.source()构建 DSL,DSL 中可以包含查询、分页、排序、高亮等query():代表查询条件,利用QueryBuilders.matchAllQuery()构建一个 match_all 查询的 DSL
- 第三步,利用
client.search()发送请求,得到响应
这里关键的 API 有两个:
- 一个是
request.source(),其中包含了查询、排序、分页、高亮等所有功能。 - 另一个是
QueryBuilders,其中包含 match、term、function_score、bool 等各种查询:
解析响应
ElasticSearch 返回的结果是一个 JSON 字符串,结构包含:
{
"took" : 0,
"timed_out" : false,
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "heima",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"info" : "Java讲师", "name" : "赵云",
}
},
// ...
]
}
}
hits:命中的结果total:总条数,其中的 value 是具体的总条数值max_score:所有结果中得分最高的文档的相关性算分hits:搜索结果的文档数组,其中的每个文档都是一个 JSON 对象_source:文档中的原始数据,也是 JSON 对象
因此,我们解析响应结果,就是逐层解析 JSON 字符串,流程如下:
@Test
void testMatchAll() throws IOException {
// ... 略
// 4.解析结果
SearchHits searchHits = response.getHits();
// 4.1.查询的总条数
long total = searchHits.getTotalHits().value;
// 4.2.查询的结果数组
SearchHit[] hits = searchHits.getHits();
for (SearchHit hit : hits) {
// 4.3.得到source
String json = hit.getSourceAsString();
// 4.4.打印
System.out.println(json);
}
}
SearchHits:通过response.getHits()获取,就是 JSON 中的最外层的hits,代表命中的结果SearchHits#getTotalHits().value:获取总条数信息SearchHits#getHits():获取 SearchHit 数组,也就是文档数组SearchHit#getSourceAsString():获取文档结果中的_source,也就是原始的 JSON 文档数据
完整代码
@Test
void testMatchAll() throws IOException {
// 1.准备 Request
SearchRequest request = new SearchRequest("hotel");
// 2.组织 DSL 参数
request.source().query(QueryBuilders.matchAllQuery());
// 3.发送请求,得到响应结果
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 4.解析结果
SearchHits searchHits = response.getHits();
// 4.1.查询的总条数
long total = searchHits.getTotalHits().value;
System.err.println("total = " + total);
// 4.2.查询的结果数组
SearchHit[] hits = searchHits.getHits();
for (SearchHit hit : hits) {
// 4.3.得到source
String json = hit.getSourceAsString();
// 反序列化
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
// 4.4.打印
System.out.println(hotelDoc);
}
}
快速入门小结
查询的基本步骤是:
- 创建 SearchRequest 对象
- 准备
Request.source(),也就是 DSL。- QueryBuilders 来构建查询条件
- 传入
Request.source()的query()方法
- 发送请求,得到结果
- 解析结果(参考 JSON 结果,从外到内,逐层解析)
match 查询
全文检索的 match 和 multi_match 查询与 match_all 的 API 基本一致。差别是查询条件,也就是 query 的部分。
GET /hotel/_search
{
"query": {
"match_all": {}
}
}
GET /hotel/_search
{
"query": {
"match": {
"all": "如家"
}
}
}
GET /hotel/_search
{
"query": {
"multi_match": {
"query": "如家",
"fields": ["brand", "name"]
}
}
}
因此,Java 代码上的差异主要是 request.source().query() 中的参数了。同样是利用 QueryBuilders 提供的方法:
// 单字段查询
QueryBuilders.matchQuery("all", "如家");
// 多字段查询
QueryBuilders.multiMatchQuery("如家", "name", "business");
而结果解析代码则完全一致,可以抽取并共享。
完整代码如下:
@Test
void testMatch() throws IOException {
// 1.准备Request
SearchRequest request = new SearchRequest("hotel");
// 2.准备DSL
request.source().query(QueryBuilders.matchQuery("all", "如家"));
// 3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 4.解析响应
handleResponse(response);
}
IDEA 代码抽取 Ctrl + Alt + M
精确查询
精确查询主要是两者:
- term:词条精确匹配
- range:范围查询
与之前的查询相比,差异同样在查询条件,其它都一样。
GET /hotel/_search
{
"query": {
"term": {
"city": "杭州"
}
}
}
GET /hotel/_search
{
"query": {
"range": {
"price": { "gte": 100, "lte": 150 }
}
}
}
查询条件构造的 API 如下:
// 词条查询
QueryBuilders.termQuery("city", "杭州");
// 范围查询
QueryBuilders.rangeQuery("price").gte(100).lte(150);
布尔查询
布尔查询是用 must、must_not、filter 等方式组合其它查询,代码示例如下:
// 创建布尔查询
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
// 添加must条件
boolQuery.must(QueryBuilders.termQuery("city", "杭州"));
// 添加filter条件
boolQuery.filter(QueryBuilders.rangeQuery("price").lte(250));
GET /hotel/_search
{
"query": {
"bool": {
"must": [
{
"term": { "city": "杭州" }
}
],
"filter": [
{
"range": {
"price": { "lte": 250 }
}
}
]
}
}
}
可以看到,API 与其它查询的差别同样是在查询条件的构建,QueryBuilders,结果解析等其他代码完全不变。
示例代码:
@Test
void testBool() throws IOException {
// 1.准备Request
SearchRequest request = new SearchRequest("hotel");
// 2.准备DSL
// 2.1.准备BooleanQuery
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
// 2.2.添加term
boolQuery.must(QueryBuilders.termQuery("city", "上海"));
// 2.3.添加range
boolQuery.filter(QueryBuilders.rangeQuery("price").lte(250));
request.source().query(boolQuery);
// 3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 4.解析响应
handleResponse(response);
}
