2、ElasticSearch高级搜索
- Elasticsearch提供了基于JSON的DSL(Domain Specific Language)来定义查询。常见的查询类型如下所示
- ①、查询所有
- 查询出所有数据,一般测试用;例如
- match_all
- 如下图所示

- ②、全文检索(full text)查询
- 利用分词器对用户输入内容分词,然后去倒排索引库中匹配,例如
- match_query
- multi_match_query
- ③、精确查询
- 根据精确词条值查找数据,一般是查找keyword、数值、日期、boolean等类型的字段,例如
- ④、地理(geo)查询
- 根据经纬度查询,例如
- geo_distance
- geo_bounding_box
- ⑤、复合(compound)查询
- 复合查询可以将上述各种查询条件组合起来,合并查询条件,例如
- bool
- function_score
2.1、全文检索查询
2.1.1、使用场景
- 全文检索查询的基本流程如下所示
- ①、对用户搜索的内容做分词,得到词条
- ②、根据词条去倒排索引库中匹配,得到文档id
- ③、根据文档id找到文档,把所有匹配结果以并集或交集返回给用户
- 比较常用的场景包括
- 因为是拿着词条去匹配,因此参与搜索的字段也必须是可分词的text类型的字段
2.1.2、DSL语句格式
- 常见的全文检索查询包括
- match查询:单字段查询
- multi_match查询:多字段查询,任意一个字段符合条件就算符合查询条件
- match查询语法如下所示
- GET /indexName/_search
- {
- "query": {
- "match":{
- "FIELD": "TEXT"
- }
- }
- }
复制代码
- match_all查询语法如下
- GET /indexName/_search
- {
- "query": {
- "multi_match": {
- "query": "TEXT",
- "fileds": ["FILED1", "FILED2"]
- }
- }
- }
复制代码
2.1.3、match查询DSL语句示例&&RestAPI示例
①、DSL语句
- 比如要搜索name字段中存在 如家酒店,DSL语句如下所示
- GET hotel/_search
- {
- "query": {
- "match": {
- "name": "如家酒店"
- }
- },
- "size": 2 # size的意思是只显示n条数据
- }
复制代码
- 搜索结果如下所示
- 结果分析
- 因为name字段是类型是text,搜索的时候会对这个字段进行分词
- 如搜索如家酒店,那么就会分词称为如家,酒店,相当于会搜索三次,并取这三次搜索的并集(ES默认的是并集),所以搜索的命中率才会如此之高
- 通俗的来说
- 并集就相当于搜索到name like %如家%算一条数据,搜索到酒店也算一条数据
- 那么交集就跟它相反,必须是name like %如家酒店%才能算是一条数据
- 那么如何取交集呢?,如下所示
- DSL
- # 取交集,并集是or
- GET hotel/_search
- {
- "query": {
- "match": {
- "name": {
- "query": "如家酒店",
- "operator": "and"
- }
- }
- }
- }
复制代码
- 运行结果
②、RestAPI
math_all
- 代码如下所示
- package com.coolman.hotel.test;
- import com.coolman.hotel.pojo.HotelDoc;
- import com.fasterxml.jackson.core.JsonProcessingException;
- import com.fasterxml.jackson.databind.ObjectMapper;
- import org.apache.lucene.search.TotalHits;
- import org.elasticsearch.action.search.SearchRequest;
- import org.elasticsearch.action.search.SearchResponse;
- import org.elasticsearch.client.RequestOptions;
- import org.elasticsearch.client.RestHighLevelClient;
- import org.elasticsearch.index.query.MatchAllQueryBuilder;
- import org.elasticsearch.index.query.QueryBuilder;
- import org.elasticsearch.index.query.QueryBuilders;
- import org.elasticsearch.search.SearchHit;
- import org.elasticsearch.search.SearchHits;
- import org.junit.jupiter.api.Test;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.boot.test.context.SpringBootTest;
- import java.io.IOException;
- @SpringBootTest
- public class FullTextSearchDemo {
- // 注入 RestHighLevelClient对象
- @Autowired
- private RestHighLevelClient restHighLevelClient;
复制代码- // jackson
- private final ObjectMapper objectMapper = new ObjectMapper();
- /**
- * 查询所有测试
- */
- @Test
- public void testMatchAll() throws IOException {
- // 1. 创建一个查询请求对象
- SearchRequest searchRequest = new SearchRequest("hotel"); // 指定索引
- // 2. 添加查询的类型
- MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
- searchRequest.source().query(matchAllQueryBuilder); // source就相当于{}
- searchRequest.source().size(100); // RestAPI默认返回的是10条数据,可以更改size的属性,即可自定义返回的数据量
- // 3. 发出查询的请求,得到响应结果
- SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
- // 4. 处理响应的结果
- handlerResponse(response);
- }
- /**
- * 用来处理响应数据(相当于解析返回的JSON数据)
- * @param response
- */
- private void handlerResponse(SearchResponse response) throws JsonProcessingException {
- // 1. 得到命中的数量(即总记录数量)
- SearchHits hits = response.getHits();
- long totalCount = hits.getTotalHits().value;// 总记录数
- System.out.println("总记录数量为:" + totalCount);
- // 2. 获取本次查询出来的列表数据
- SearchHit[] hitsArray = hits.getHits();
- for (SearchHit hit : hitsArray) {
- // 得到json字符串
- String json = hit.getSourceAsString();
- // 将json字符串转换为实体类对象
- HotelDoc hotelDoc = objectMapper.readValue(json, HotelDoc.class);
- System.out.println(hotelDoc);
- }
- }
复制代码 }
~~~
match
- 代码如下所示
- /**
- * 单字段查询
- */
- @Test
- public void testMatch() throws IOException {
- // 1. 创建查询请求对象
- SearchRequest searchRequest = new SearchRequest("hotel");
- // 2. 添加查询的类型
- MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("name", "如家酒店");
- searchRequest.source().query(matchQueryBuilder);
- // 3. 发出查询请求,得到响应数据
- SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
- // 4. 处理响应的结果
- handlerResponse(response);
- }
复制代码
自行运行查看结果即可
2.1.4、multi_match查询DSL语句示例&&RestAPI示例
DSL语句
- 比如搜索name和brand字段中出现如家酒店的数据
- DSL语句如下所示
- GET hotel/_search
- {
- "query": {
- "multi_match": {
- "query": "如家酒店",
- "fields": ["name", "brand"]
- }
- }
- }
复制代码
- 运行结果如下所示
- 不过多字段查询的使用很少,因为多字段查询会使得查询效率变慢
- 一般都会在创建映射的时候,使用copy_to将指定字段的值拷贝到另一个字段,如自定义的all字段
- 这样子就可以使用单字段查询,提高查询效率
RestAPI
跟单字段查询差不多,只不过使用QueryBuilders创建的对象略有不同罢了
- 代码如下所示
- /**
- * 多字段查询
- */
- @Test
- public void testMultiMatch() throws IOException {
- // 1. 创建查询请求球体对象
- SearchRequest searchRequest = new SearchRequest("hotel");
- // 2. 添加要查询的字段
- // MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("如家酒店", "name", "brand", "bussiness");
- // searchRequest.source().query(multiMatchQueryBuilder);
- // 因为在创建映射的时候使用了copy_to,索引上面的多字段查询等价于下面的单字段查询
- MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("all", "如家酒店");
- searchRequest.source().query(matchQueryBuilder);
- // 3. 执行查询操作,得到响应对象
- SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
- // 4. 处理响应对象
- handlerResponse(response);
- }
复制代码
2.2、精准查询
2.2.1、使用场景
<ul>精确查询一般是查找keyword、数值、日期、boolean等类型的字段,所以不会对搜索条件分词,常见的有如下<ul>
term
range<ul>
根据值的范围查询,相当于>=、 |