目录
查询DSL的基本语法是什么?
GET/索引库名/_search
{ "query": { "查询类型":{ "FIELD": "TET"}}}
match和multi_match的区别是什么?
1、match:根据一个字段查询
2、multi_match:根据多个字段查询,参与查询字段越多,查询性能越差
精确查询常见的有哪些?
1、term查询:根据词条精确匹配,一般搜索keyword类型、数值类型、布尔类型、日期类型字段
2、range查询:根据数值范围查询,可以是数值、日期的范围
elasticsearch中的相关性打分算法是什么?
1、TF-IDF:在elasticsearch5.0之前,会随着词频增加而越来越大
2、BM25:在elasticsearch5.0之后,会随着词频增加而增大,但增长曲线会趋于水平
function score query定义的三要素是什么?
1、过滤条件:哪些文档要加分
2、算分函数:如何计算function score
3、加权方式:function score 与query score如何运算
bool查询有几种逻辑关系?
1、must:必须匹配的条件,可以理解为“与”
2、should:选择性匹配的条件,可以理解为“或”
3、must_not:必须不匹配的条件,不参与打分
4、filter:必须匹配的条件,不参与打分
from + size:
1、优点:支持随机翻页
2、缺点:深度分页问题,默认查询上限(from + size)是100003、场景:百度、京东、谷歌、淘宝这样的随机翻页搜索
after search:
1、优点:没有查询上限(单次查询的size不超过10000)2、缺点:只能向后逐页查询,不支持随机翻页
3、场景:没有随机翻页需求的搜索,例如手机向下滚动翻页scroll:
1、优点:没有查询上限(单次查询的size不超过10000 )2、缺点:会有额外内存消耗,并且搜索结果是非实时的
3、场景:海量数据的获取和迁移。从ES7.1开始不推荐,建议用aftersearch方案。
查询的基本步骤是:
1、创建SearchRequest对象
2、准备Request.source(),也就是DSL。
2.1、QueryBuilders来构建查询条件
2.2、传入Request.source()的query()方法3、发送请求,得到结果
4、解析结果(参考JSON结果,从外到内,逐层解析)
要构建查询条件,只要记住一个类:QueryBuilders
1、所有搜索DSL的构建,记住一个API:SearchRequest的source()方法。
2、高亮结果解析是参考JSON结果,逐层解析
Elasticsearch提供了基于JSON的DSL (Domain Specific Language)来定义查询。
常见的查询
查询所有:查询出所有数据,一般测试用。例如: match_all
全文检索(full text)查询:利用分词器对用户输入内容分词,然后去倒排索引库中匹配。例如:
1、match_query
2、multi_match_query
精确查询:根据精确词条值查找数据,一般是查找keyword、数值、日期、boolean等类型字段。例如:
1、ids
2、range3、term
地理(geo)查询:根据经纬度查询。例如∶
1、geo_distance
2、geo_bounding_box
复合(compound)查询:复合查询可以将上述各种查询条件组合起来,合并查询条件。例如;
1、bool
2、function_score
GET /hotel/_search
{
"query": {
"match_all": {}
}
}
match查询:全文检索查询的一种,会对用户输入内容分词,然后去倒排索引库检索
GET /hotel/_search
{
"query": {
"match": {
"all": "外滩如家"
}
}
}
因为外滩如家可以分词为:外滩、如家。所以可以查询到包含着两个词之一的内容?
multi_match: 与match查询类似,只不过允许同时查询多个字段
GET /hotel/_search
{
"query": {
"multi_match": {
"query": "外滩如家",
"fields": ["brand","name","business"]
}
}
}
查询brand,name,business之一包含外滩、如家之一的内容
精确查询一般是查找keyword、数值、日期、boolean等类型字段。所以不会对搜索条件分词
term查询:根据词条精准值查询
GET /hotel/_search
{
"query": {
"term": {
"city": {
"value": "上海"
}
}
}
}
city中必须为上海,包含“上海”但是不只有这两个字也不能查询到
range查询:根据值的范围查询
GET /hotel/_search
{
"query": {
"range": {
"price": {
"gte": 1008,
"lte": 3000
}
}
}
}
price大于等于100,小于等于300?。没有e就是没有等于
根据经纬度查询
geo bounding box:查询geo_point值落在某个矩形范围的所有文档
GET /indexName/_search
{
? "query": {
? ? "geo_bounding_box": {
? ? ? ?"FIELD": {
? ? ? ? ?"top_left": {
? ? ? ? ? ?"lat": 31.1,
? ? ? ? ? ?"lon": 121.5
? ? ? ? ?},
? ? ? ? ?"bottom_right": {
? ? ? ? ? ?"lat": 30.9,
? ? ? ? ? ?"lon": 121.7
? ? ? ? ?}
? ? ? ?}
? ? }
? }
}
geo_distance:查询到指定中心点小于某个距离值的所有文档
GET /hotel/_search
{
"query": {
"geo_distance": {
"distance": "1km",
"location": "31.21, 121.5"
}
}
}
查询到的都是距离31.21,121.5不超过1km的内容?
复合(compound)查询:复合查询可以将其它简单查询组合起来,实现更复杂的搜索逻辑
fuction score:算分函数查询,可以控制文档相关性算分,控制文档排名
当我们利用match查询时,文档结果会根据与搜索词条的关联度打分(_score),返回结果时按照分值降序排列
使用function score query,可以修改文档的相关性算分(query score),根据新得到的算分排序。
原始查询条件,搜索文档并根据相关性打分(query score)
"query": {
? ? "match": {
? ? ? ? ? ? "all": "外滩"
? ? ? ? ? }
? ? ? ? },
过滤条件,符合条件的文档才会被重新算分
"filter": {
? ? ? ? ? ? "term": {
? ? ? ? ? ? ? "id": "1"
? ? ? ? ? ? }
? ? ? ? ? },?
算分函数,算分函数的结果称为function score ,将来会与queryscore运算,得到新算分
常见的算分函数有:
1、weight:给一个常量值,作为函数结果(function score)2、field_value_factor:用文档中的某个字段值作为函数结果
3、random_score:随机生成一个值,作为函数结果
4、script_score:自定义计算公式,公式结果作为函数结果"weight": 10?
加权模式,定义function score与query score的运算方式
包括:
1、multiply:两者相乘。默认就是这个
2、replace:用function score替换query score3、其它: sum、avg、max、min
"boost_mode": "mutliply"?
GET /hotel/_search
{
"query": {
"function_score": {
"query": {
"match": {
"all": "外滩"
}
},
"functions": [
{
"filter": {
"term": {
"brand": "如家"
}
},
"weight": 10
}
],
"boost_mode": "sum"
}
}
}
满足条件的内容权重会+10,使得它会在更前面?
布尔查询是一个或多个查询子句的组合
子查询的组合方式有:
1、must:必须匹配每个子查询,类似“与”
2、should:选择性匹配子查询,类似“或”
3、must_not:必须不匹配,不参与算分,类似“非”4、filter:必须匹配,不参与算分
GET /hotel/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"name": "如家"
}
}
],
"must_not": [
{
"range": {
"price": {
"gt": 400
}
}
}
],
"filter": [
{
"geo_distance": {
"distance": "10km",
"location": {
"lat": 31.21,
"lon": 121.5
}
}
}
]
}
}
}
name必须为“如家”,价格必须不大于400,地理在31.21,121.5不超过10km的内容
?elasticsearch支持对搜索结果排序,默认是根据相关度算分(_score)来排序
可以排序字段类型有::keyword类型、数值类型、地理坐标类型、日期类型等
GET /hotel/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"score": "desc"
},
{
"price": "asc"
}
]
}
先根据score降序,再根据price升序?
GET /hotel/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"_geo_distance": {
"location": {
"lat": 31.034661,
"lon": 121.612282
},
"order": "asc",
"unit": "km"
}
}
]
}
找到121.612282,31.034661周围的酒店,距离升序排序,单位为km
elasticsearch默认情况下只返回top10的数据。而如果要查询更多数据就需要修改分页参数了
elasticsearch中通过修改from、size参数来控制要返回的分页结果
GET /hotel/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"price": "asc"
}
],
"from": 0,
"size": 10
}
从第0页开始,每页10个。所以这里查到的是前10个?
ES是分布式的,所以会面临深度分页问题。
1、首先在每个数据分片上都排序并查询前1000条文档。
2、然后将所有节点的结果聚合,在内存中重新排序选出前1000条文档
3、最后从这1000条中,选取从990开始的10条文档
如果搜索页数过深,或者结果集(from + size)越大,对内存和CPU的消耗也越高。因此ES设定结果集查询的上限是10000
GET /hotel/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"price": "asc"
}
],
"from": 9991,
"size": 10
}
从9991页开始,每页10个,则会查到第10001个数据。报错
针对深度分页,ES提供了两种解决方案
1、search after:分页时需要排序,原理是从上一次的排序值开始,查询下一页数据。官方推荐使用的方式。
2、scroll:原理将排序数据形成快照,保存在内存。官方已经不推荐使用。
高亮:就是在搜索结果中把搜索关键字突出显示。
原理是这样的:
1、将搜索结果中的关键字用标签标记出来2、在页面中给标签添加css样式
默认情况下,搜索字段必须与高亮字段一致才能高亮。
这里的"require_field_match": "false",就让搜索字段不需要与高亮字段一致也能高亮
GET /hotel/_search
{
"query": {
"match": {
"all": "如家"
}
},
"highlight": {
"fields": {
"name": {
"require_field_match": "false"
}
}
}
}
name为“如家”的位置加上了css的高亮标签了。源部分不会有高亮标签,highlight才部分才有高亮标签
hotel-demo和sqlhttps://pan.baidu.com/s/10SEnZ93I2_TB6ig8WlxvjQ?pwd=955e
RestAPI中其中构建DSL是通过HighLevelRestClient中的resource()来实现的,其中包含了查询、排序、分页、高亮等
RestAPI中其中构建查询条件的核心部分是由一个名为QueryBuilders的工具类提供的,其中包含了各种查询方法
我们通过match_all来演示下基本的API?
SearchRequest request = new SearchRequest("hotel");
相当于
GET /indexName/_search
query(QueryBuilders.matchAllQuery()
相当于
?"query": {
? ? "match_all": {}
? }
@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、解析响应 handleResponse(response); }private void handleResponse(SearchResponse response) { //4、解析响应 SearchHits searchHits = response.getHits(); //4.1获取总条数 long total = searchHits.getTotalHits().value; System.out.println("共搜索到" + total + "条数据"); //4.2文档数组 SearchHit[] hits = searchHits.getHits(); //4.3遍历 for (SearchHit hit : hits) { //获取文档source String json = hit.getSourceAsString(); //反序列化 HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class); System.out.println("hotelDoc = " + hotelDoc); } System.out.println(response); }
package cn.itcast.hotel;
import cn.itcast.hotel.pojo.HotelDoc;
import com.alibaba.fastjson.JSON;
import org.apache.http.HttpHost;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.Rewriteable;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.SuggestBuilders;
import org.elasticsearch.search.suggest.completion.CompletionSuggester;
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.util.CollectionUtils;
import javax.naming.directory.SearchResult;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import static cn.itcast.hotel.constants.HotelConstants.MAPPING_TEMPLATE;
public class HotelSearchTest {
private RestHighLevelClient client;
@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、解析响应
handleResponse(response);
}
private void handleResponse(SearchResponse response) {
//4、解析响应
SearchHits searchHits = response.getHits();
//4.1获取总条数
long total = searchHits.getTotalHits().value;
System.out.println("共搜索到" + total + "条数据");
//4.2文档数组
SearchHit[] hits = searchHits.getHits();
//4.3遍历
for (SearchHit hit : hits) {
//获取文档source
String json = hit.getSourceAsString();
//反序列化
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
System.out.println("hotelDoc = " + hotelDoc);
}
System.out.println(response);
}
@BeforeEach
void setUp() {
this.client = new RestHighLevelClient(RestClient.builder(
HttpHost.create("http://192.168.80.130:9200")
));
}
@AfterEach
void tearDown() throws IOException {
this.client.close();
}
}
查询到了所有的数据?
?
全文检索的match和multi_match查询与match_all的API基本一致。差别是查询条件,也就是query的部分
//单字段查询
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); }?private void handleResponse(SearchResponse response) {
? ? ? ? //4、解析响应
? ? ? ? SearchHits searchHits = response.getHits();
? ? ? ? //4.1获取总条数
? ? ? ? long total = searchHits.getTotalHits().value;
? ? ? ? System.out.println("共搜索到" + total + "条数据");
? ? ? ? //4.2文档数组
? ? ? ? SearchHit[] hits = searchHits.getHits();
? ? ? ? //4.3遍历
? ? ? ? for (SearchHit hit : hits) {
? ? ? ? ? ? //获取文档source
? ? ? ? ? ? String json = hit.getSourceAsString();
? ? ? ? ? ? //反序列化
? ? ? ? ? ? HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
? ? ? ? ? ? System.out.println("hotelDoc = " + hotelDoc);
? ? ? ? }
? ? ? ? System.out.println(response);
? ? }
package cn.itcast.hotel;
import cn.itcast.hotel.pojo.HotelDoc;
import com.alibaba.fastjson.JSON;
import org.apache.http.HttpHost;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.Rewriteable;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.SuggestBuilders;
import org.elasticsearch.search.suggest.completion.CompletionSuggester;
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.util.CollectionUtils;
import javax.naming.directory.SearchResult;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import static cn.itcast.hotel.constants.HotelConstants.MAPPING_TEMPLATE;
public class HotelSearchTest {
private RestHighLevelClient client;
@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、解析响应
handleResponse(response);
}
@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);
}
private void handleResponse(SearchResponse response) {
//4、解析响应
SearchHits searchHits = response.getHits();
//4.1获取总条数
long total = searchHits.getTotalHits().value;
System.out.println("共搜索到" + total + "条数据");
//4.2文档数组
SearchHit[] hits = searchHits.getHits();
//4.3遍历
for (SearchHit hit : hits) {
//获取文档source
String json = hit.getSourceAsString();
//反序列化
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
System.out.println("hotelDoc = " + hotelDoc);
}
System.out.println(response);
}
@BeforeEach
void setUp() {
this.client = new RestHighLevelClient(RestClient.builder(
HttpHost.create("http://192.168.80.130:9200")
));
}
@AfterEach
void tearDown() throws IOException {
this.client.close();
}
}
查询到了带有“如家”的数据?
?
精确查询常见的有term查询和range查询,同样利用QueryBuilders实现
//词条查询
QueryBuilders.termQuery ( "city","杭州");//范围查询
QueryBuilders.rangeQuery( "price").gte( 100).lte( 150);?
精确查询常见的有term查询和range查询,同样利用QueryBuilders实现
//创建布尔查询
BoolQueryBuilder boolQuery = QueryBuilders.bgolQuery();//添加must条件
boolQuery.must(QueryBuilders.termQuery("city","杭州"));//添加filter条件
boolQuery.filter(QueryBuilders.rangeQuery("price").lte(250));
@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); }?? private void handleResponse(SearchResponse response) {
? ? ? ? //4、解析响应
? ? ? ? SearchHits searchHits = response.getHits();
? ? ? ? //4.1获取总条数
? ? ? ? long total = searchHits.getTotalHits().value;
? ? ? ? System.out.println("共搜索到" + total + "条数据");
? ? ? ? //4.2文档数组
? ? ? ? SearchHit[] hits = searchHits.getHits();
? ? ? ? //4.3遍历
? ? ? ? for (SearchHit hit : hits) {
? ? ? ? ? ? //获取文档source
? ? ? ? ? ? String json = hit.getSourceAsString();
? ? ? ? ? ? //反序列化
? ? ? ? ? ? HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
? ? ? ? ? ? System.out.println("hotelDoc = " + hotelDoc);
? ? ? ? }
? ? ? ? System.out.println(response);
? ? }
package cn.itcast.hotel;
import cn.itcast.hotel.pojo.HotelDoc;
import com.alibaba.fastjson.JSON;
import org.apache.http.HttpHost;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.Rewriteable;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.SuggestBuilders;
import org.elasticsearch.search.suggest.completion.CompletionSuggester;
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.util.CollectionUtils;
import javax.naming.directory.SearchResult;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import static cn.itcast.hotel.constants.HotelConstants.MAPPING_TEMPLATE;
public class HotelSearchTest {
private RestHighLevelClient client;
@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、解析响应
handleResponse(response);
}
@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);
}
@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);
}
private void handleResponse(SearchResponse response) {
//4、解析响应
SearchHits searchHits = response.getHits();
//4.1获取总条数
long total = searchHits.getTotalHits().value;
System.out.println("共搜索到" + total + "条数据");
//4.2文档数组
SearchHit[] hits = searchHits.getHits();
//4.3遍历
for (SearchHit hit : hits) {
//获取文档source
String json = hit.getSourceAsString();
//反序列化
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
System.out.println("hotelDoc = " + hotelDoc);
}
System.out.println(response);
}
@BeforeEach
void setUp() {
this.client = new RestHighLevelClient(RestClient.builder(
HttpHost.create("http://192.168.80.130:9200")
));
}
@AfterEach
void tearDown() throws IOException {
this.client.close();
}
}
查询出city必须是上海,price必须小于等于250的数据?
?
搜索结果的排序和分页是与query同级的参数
//查询
request.source().query(QueryBuilders.matchAllQuery());//分页
request.source( ).from(0).size(5);//价格排序
request.source().sort("price",SortOrder.ASC);
@Test void testRageAndSort() throws IOException { //页码,每页大小 int page = 2, size = 5; //1、准备Request SearchRequest request = new SearchRequest("hotel"); //2、准备DSL //2.1、准备query request.source().query(QueryBuilders.matchAllQuery()); //2.2、排序sort request.source().sort("price", SortOrder.ASC); //2.3、分页from,size request.source().from((page - 1) * size).size(5); //3、发送请求 SearchResponse response = client.search(request, RequestOptions.DEFAULT); //4、解析响应 handleResponse(response); }? ? private void handleResponse(SearchResponse response) {
? ? ? ? //4、解析响应
? ? ? ? SearchHits searchHits = response.getHits();
? ? ? ? //4.1获取总条数
? ? ? ? long total = searchHits.getTotalHits().value;
? ? ? ? System.out.println("共搜索到" + total + "条数据");
? ? ? ? //4.2文档数组
? ? ? ? SearchHit[] hits = searchHits.getHits();
? ? ? ? //4.3遍历
? ? ? ? for (SearchHit hit : hits) {
? ? ? ? ? ? //获取文档source
? ? ? ? ? ? String json = hit.getSourceAsString();
? ? ? ? ? ? //反序列化
? ? ? ? ? ? HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
? ? ? ? ? ? System.out.println("hotelDoc = " + hotelDoc);
? ? ? ? }
? ? ? ? System.out.println(response);
? ? }
package cn.itcast.hotel;
import cn.itcast.hotel.pojo.HotelDoc;
import com.alibaba.fastjson.JSON;
import org.apache.http.HttpHost;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.Rewriteable;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.SuggestBuilders;
import org.elasticsearch.search.suggest.completion.CompletionSuggester;
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.util.CollectionUtils;
import javax.naming.directory.SearchResult;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import static cn.itcast.hotel.constants.HotelConstants.MAPPING_TEMPLATE;
public class HotelSearchTest {
private RestHighLevelClient client;
@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、解析响应
handleResponse(response);
}
@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);
}
@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);
}
@Test
void testRageAndSort() throws IOException {
//页码,每页大小
int page = 2, size = 5;
//1、准备Request
SearchRequest request = new SearchRequest("hotel");
//2、准备DSL
//2.1、准备query
request.source().query(QueryBuilders.matchAllQuery());
//2.2、排序sort
request.source().sort("price", SortOrder.ASC);
//2.3、分页from,size
request.source().from((page - 1) * size).size(5);
//3、发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//4、解析响应
handleResponse(response);
}
private void handleResponse(SearchResponse response) {
//4、解析响应
SearchHits searchHits = response.getHits();
//4.1获取总条数
long total = searchHits.getTotalHits().value;
System.out.println("共搜索到" + total + "条数据");
//4.2文档数组
SearchHit[] hits = searchHits.getHits();
//4.3遍历
for (SearchHit hit : hits) {
//获取文档source
String json = hit.getSourceAsString();
//反序列化
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
System.out.println("hotelDoc = " + hotelDoc);
}
System.out.println(response);
}
@BeforeEach
void setUp() {
this.client = new RestHighLevelClient(RestClient.builder(
HttpHost.create("http://192.168.80.130:9200")
));
}
@AfterEach
void tearDown() throws IOException {
this.client.close();
}
}
查询第二页,每页大小为5?
?
高亮API包括请求DSL构建和结果解析两部分
request.source().highlighter(new HighlightBuilder().field("name").requireFieldMatch(false));
@Test void testHighlight() throws IOException { //1、准备Request SearchRequest request = new SearchRequest("hotel"); //2、准备DSL //2.1、query request.source().query(QueryBuilders.matchQuery("all","如家")); //2.2、高亮 request.source().highlighter(new HighlightBuilder().field("name").requireFieldMatch(false)); //3、发送请求 SearchResponse response = client.search(request, RequestOptions.DEFAULT); //4、解析响应 handleResponse(response); }private void handleResponse(SearchResponse response) { //4、解析响应 SearchHits searchHits = response.getHits(); //4.1获取总条数 long total = searchHits.getTotalHits().value; System.out.println("共搜索到" + total + "条数据"); //4.2文档数组 SearchHit[] hits = searchHits.getHits(); //4.3遍历 for (SearchHit hit : hits) { //获取文档source String json = hit.getSourceAsString(); //反序列化 HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class); //获取高亮结果 Map<String, HighlightField> highlightFields = hit.getHighlightFields(); //判断是否有高亮结果 if(!CollectionUtils.isEmpty(highlightFields)){ //根据字段名获取高亮结果 HighlightField highlightField = highlightFields.get("name"); //判断是否有字段名高亮 if(highlightField != null){ //获取高亮值 String name = highlightField.getFragments()[0].string(); //覆盖非高亮结果 hotelDoc.setName(name); } } System.out.println("hotelDoc = " + hotelDoc); } System.out.println(response); }
package cn.itcast.hotel;
import cn.itcast.hotel.pojo.HotelDoc;
import com.alibaba.fastjson.JSON;
import org.apache.http.HttpHost;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.Rewriteable;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.SuggestBuilders;
import org.elasticsearch.search.suggest.completion.CompletionSuggester;
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.util.CollectionUtils;
import javax.naming.directory.SearchResult;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import static cn.itcast.hotel.constants.HotelConstants.MAPPING_TEMPLATE;
public class HotelSearchTest {
private RestHighLevelClient client;
@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、解析响应
handleResponse(response);
}
@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);
}
@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);
}
@Test
void testRageAndSort() throws IOException {
//页码,每页大小
int page = 2, size = 5;
//1、准备Request
SearchRequest request = new SearchRequest("hotel");
//2、准备DSL
//2.1、准备query
request.source().query(QueryBuilders.matchAllQuery());
//2.2、排序sort
request.source().sort("price", SortOrder.ASC);
//2.3、分页from,size
request.source().from((page - 1) * size).size(5);
//3、发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//4、解析响应
handleResponse(response);
}
@Test
void testHighlight() throws IOException {
//1、准备Request
SearchRequest request = new SearchRequest("hotel");
//2、准备DSL
//2.1、query
request.source().query(QueryBuilders.matchQuery("all","如家"));
//2.2、高亮
request.source().highlighter(new HighlightBuilder().field("name").requireFieldMatch(false));
//3、发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//4、解析响应
handleResponse(response);
}
private void handleResponse(SearchResponse response) {
//4、解析响应
SearchHits searchHits = response.getHits();
//4.1获取总条数
long total = searchHits.getTotalHits().value;
System.out.println("共搜索到" + total + "条数据");
//4.2文档数组
SearchHit[] hits = searchHits.getHits();
//4.3遍历
for (SearchHit hit : hits) {
//获取文档source
String json = hit.getSourceAsString();
//反序列化
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
//获取高亮结果
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
//判断是否有高亮结果
if(!CollectionUtils.isEmpty(highlightFields)){
//根据字段名获取高亮结果
HighlightField highlightField = highlightFields.get("name");
//判断是否有字段名高亮
if(highlightField != null){
//获取高亮值
String name = highlightField.getFragments()[0].string();
//覆盖非高亮结果
hotelDoc.setName(name);
}
}
System.out.println("hotelDoc = " + hotelDoc);
}
System.out.println(response);
}
@BeforeEach
void setUp() {
this.client = new RestHighLevelClient(RestClient.builder(
HttpHost.create("http://192.168.80.130:9200")
));
}
@AfterEach
void tearDown() throws IOException {
this.client.close();
}
}
查询所以内容中有“如家”的数据,并把name加上css的高亮标签?
?
在pojo包下创建一个RequestParams.java
package cn.itcast.hotel.pojo;
import lombok.Data;
@Data
public class RequestParams {
private String key;
private Integer page;
private Integer size;
private String sortBy;
}
在pojo包下创建一个PageResult.java
package cn.itcast.hotel.pojo;
import lombok.Data;
import java.util.List;
@Data
public class PageResult {
private Long total;
private List<HotelDoc> hotels;
public PageResult(Long total, List<HotelDoc> hotels) {
this.total = total;
this.hotels = hotels;
}
public PageResult() {
}
}
创建一个web包,下面创建一个HotelController.java
@PostMapping("/list") public PageResult search(@RequestBody RequestParams params){ return hotelService.search(params); }
package cn.itcast.hotel.web;
import cn.itcast.hotel.pojo.PageResult;
import cn.itcast.hotel.pojo.RequestParams;
import cn.itcast.hotel.service.IHotelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/hotel")
public class HotelController {
@Autowired
private IHotelService hotelService;
@PostMapping("/list")
public PageResult search(@RequestBody RequestParams params){
return hotelService.search(params);
}
}
IHotelService.java
PageResult search(RequestParams params);
package cn.itcast.hotel.service;
import cn.itcast.hotel.pojo.Hotel;
import cn.itcast.hotel.pojo.PageResult;
import cn.itcast.hotel.pojo.RequestParams;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
import java.util.Map;
public interface IHotelService extends IService<Hotel> {
PageResult search(RequestParams params);
}
HotelService.java
@Override public PageResult search(RequestParams params) { try { //1、准备Request SearchRequest request = new SearchRequest("hotel"); //2、准备DSL //2.1、query String key = params.getKey(); ????????if(key == null || "".equals(key)){ ????????????????request.source().query(QueryBuilders.matchAllQuery()); ??????? }else{ ????????????????request.source().query(QueryBuilders.matchQuery("all",key)); ????????} //2.2、分页 int page = params.getPage(); int size = params.getSize(); request.source().from((page - 1) * size).size(size); //3、发送请求 SearchResponse response = client.search(request, RequestOptions.DEFAULT); //4、解析响应 return handleResponse(response); } catch (IOException e) { throw new RuntimeException(e); } }private PageResult handleResponse(SearchResponse response) { //4、解析响应 SearchHits searchHits = response.getHits(); //4.1获取总条数 long total = searchHits.getTotalHits().value; //4.2文档数组 SearchHit[] hits = searchHits.getHits(); //4.3遍历 List<HotelDoc> hotels = new ArrayList<>(); for (SearchHit hit : hits) { //获取文档source String json = hit.getSourceAsString(); //反序列化 HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class); hotels.add(hotelDoc); } //4、封装返回 return new PageResult(total,hotels); }
package cn.itcast.hotel.service.impl;
import cn.itcast.hotel.mapper.HotelMapper;
import cn.itcast.hotel.pojo.Hotel;
import cn.itcast.hotel.pojo.HotelDoc;
import cn.itcast.hotel.pojo.PageResult;
import cn.itcast.hotel.pojo.RequestParams;
import cn.itcast.hotel.service.IHotelService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.lucene.queries.function.FunctionScoreQuery;
import org.apache.lucene.search.vectorhighlight.ScoreOrderFragmentsBuilder;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
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.common.geo.GeoPoint;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.SuggestBuilders;
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class HotelService extends ServiceImpl<HotelMapper, Hotel> implements IHotelService {
@Autowired
private RestHighLevelClient client;
@Override
public PageResult search(RequestParams params) {
try {
//1、准备Request
SearchRequest request = new SearchRequest("hotel");
//2、准备DSL
//2.1、query
String key = params.getKey();
????????if(key == null || "".equals(key)){
????????????????request.source().query(QueryBuilders.matchAllQuery());
??????? }else{
????????????????request.source().query(QueryBuilders.matchQuery("all",key));
????????}
//2.2、分页
int page = params.getPage();
int size = params.getSize();
request.source().from((page - 1) * size).size(size);
//3、发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//4、解析响应
return handleResponse(response);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private PageResult handleResponse(SearchResponse response) {
//4、解析响应
SearchHits searchHits = response.getHits();
//4.1获取总条数
long total = searchHits.getTotalHits().value;
//4.2文档数组
SearchHit[] hits = searchHits.getHits();
//4.3遍历
List<HotelDoc> hotels = new ArrayList<>();
for (SearchHit hit : hits) {
//获取文档source
String json = hit.getSourceAsString();
//反序列化
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
hotels.add(hotelDoc);
}
//4、封装返回
return new PageResult(total,hotels);
}
}
HotelDemoApplication.java
@Bean public RestHighLevelClient client(){ return new RestHighLevelClient(RestClient.builder( HttpHost.create("http://xxx.xxx.xxx.xxx:9200") )); }
package cn.itcast.hotel;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@MapperScan("cn.itcast.hotel.mapper")
@SpringBootApplication
public class HotelDemoApplication {
public static void main(String[] args) {
SpringApplication.run(HotelDemoApplication.class, args);
}
@Bean
public RestHighLevelClient client(){
return new RestHighLevelClient(RestClient.builder(
HttpHost.create("http://xxx.xxx.xxx.xxx:9200")
));
}
}
此时搜索部分完成
?
RequestParams.java
package cn.itcast.hotel.pojo;
import lombok.Data;
@Data
public class RequestParams {
private String key;
private Integer page;
private Integer size;
private String sortBy;
private String city;
private String brand;
private String starName;
private Integer minPrice;
private Integer maxPrice;
}
HotelService.java
@Override public PageResult search(RequestParams params) { try { //1、准备Request SearchRequest request = new SearchRequest("hotel"); //2、准备DSL //2.1、query buildBasicQuery(params,request); //2.2、分页 int page = params.getPage(); int size = params.getSize(); request.source().from((page - 1) * size).size(size); //3、发送请求 SearchResponse response = client.search(request, RequestOptions.DEFAULT); //4、解析响应 return handleResponse(response); } catch (IOException e) { throw new RuntimeException(e); } }private void buildBasicQuery(RequestParams params, SearchRequest request) { //构建BooleanQuery BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); //关键字搜索 String key = params.getKey(); if(key == null || "".equals(key)){ boolQuery.must(QueryBuilders.matchAllQuery()); }else{ boolQuery.must(QueryBuilders.matchQuery("all",key)); } //城市条件 if(params.getCity() != null && !"".equals(params.getCity())){ boolQuery.filter(QueryBuilders.termQuery("city", params.getCity())); } //品牌条件 if(params.getBrand() != null && !"".equals(params.getBrand())){ boolQuery.filter(QueryBuilders.termQuery("brand", params.getBrand())); } //星级条件 if(params.getStarName() != null && !"".equals(params.getStarName())){ boolQuery.filter(QueryBuilders.termQuery("starName", params.getStarName())); } //价格 if(params.getMinPrice() != null && params.getMaxPrice() != null){ boolQuery.filter(QueryBuilders.rangeQuery("price").gte(params.getMinPrice()).lte(params.getMaxPrice())); } request.source().query(functionScoreQueryBuilder); } private PageResult handleResponse(SearchResponse response) { //4、解析响应 SearchHits searchHits = response.getHits(); //4.1获取总条数 long total = searchHits.getTotalHits().value; //4.2文档数组 SearchHit[] hits = searchHits.getHits(); //4.3遍历 List<HotelDoc> hotels = new ArrayList<>(); for (SearchHit hit : hits) { //获取文档source String json = hit.getSourceAsString(); //反序列化 HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class); hotels.add(hotelDoc); } //4、封装返回 return new PageResult(total,hotels); }
package cn.itcast.hotel.service.impl;
import cn.itcast.hotel.mapper.HotelMapper;
import cn.itcast.hotel.pojo.Hotel;
import cn.itcast.hotel.pojo.HotelDoc;
import cn.itcast.hotel.pojo.PageResult;
import cn.itcast.hotel.pojo.RequestParams;
import cn.itcast.hotel.service.IHotelService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.lucene.queries.function.FunctionScoreQuery;
import org.apache.lucene.search.vectorhighlight.ScoreOrderFragmentsBuilder;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
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.common.geo.GeoPoint;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.SuggestBuilders;
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class HotelService extends ServiceImpl<HotelMapper, Hotel> implements IHotelService {
@Autowired
private RestHighLevelClient client;
@Override
public PageResult search(RequestParams params) {
try {
//1、准备Request
SearchRequest request = new SearchRequest("hotel");
//2、准备DSL
//2.1、query
buildBasicQuery(params,request);
//2.2、分页
int page = params.getPage();
int size = params.getSize();
request.source().from((page - 1) * size).size(size);
//3、发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//4、解析响应
return handleResponse(response);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private void buildBasicQuery(RequestParams params, SearchRequest request) {
//构建BooleanQuery
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
//关键字搜索
String key = params.getKey();
if(key == null || "".equals(key)){
boolQuery.must(QueryBuilders.matchAllQuery());
}else{
boolQuery.must(QueryBuilders.matchQuery("all",key));
}
//城市条件
if(params.getCity() != null && !"".equals(params.getCity())){
boolQuery.filter(QueryBuilders.termQuery("city", params.getCity()));
}
//品牌条件
if(params.getBrand() != null && !"".equals(params.getBrand())){
boolQuery.filter(QueryBuilders.termQuery("brand", params.getBrand()));
}
//星级条件
if(params.getStarName() != null && !"".equals(params.getStarName())){
boolQuery.filter(QueryBuilders.termQuery("starName", params.getStarName()));
}
//价格
if(params.getMinPrice() != null && params.getMaxPrice() != null){ boolQuery.filter(QueryBuilders.rangeQuery("price").gte(params.getMinPrice()).lte(params.getMaxPrice()));
}
request.source().query(functionScoreQueryBuilder);
}
private PageResult handleResponse(SearchResponse response) {
//4、解析响应
SearchHits searchHits = response.getHits();
//4.1获取总条数
long total = searchHits.getTotalHits().value;
//4.2文档数组
SearchHit[] hits = searchHits.getHits();
//4.3遍历
List<HotelDoc> hotels = new ArrayList<>();
for (SearchHit hit : hits) {
//获取文档source
String json = hit.getSourceAsString();
//反序列化
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
hotels.add(hotelDoc);
}
//4、封装返回
return new PageResult(total,hotels);
}
}
此时结果可以过滤了
?
RequestParams.java
package cn.itcast.hotel.pojo;
import lombok.Data;
@Data
public class RequestParams {
private String key;
private Integer page;
private Integer size;
private String sortBy;
private String city;
private String brand;
private String starName;
private Integer minPrice;
private Integer maxPrice;
private String location;
}
HotelDoc.java
package cn.itcast.hotel.pojo;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.*;
@Data
@NoArgsConstructor
public class HotelDoc {
private Long id;
private String name;
private String address;
private Integer price;
private Integer score;
private String brand;
private String city;
private String starName;
private String business;
private String location;
private String pic;
private Object distance;
public HotelDoc(Hotel hotel) {
this.id = hotel.getId();
this.name = hotel.getName();
this.address = hotel.getAddress();
this.price = hotel.getPrice();
this.score = hotel.getScore();
this.brand = hotel.getBrand();
this.city = hotel.getCity();
this.starName = hotel.getStarName();
this.business = hotel.getBusiness();
this.location = hotel.getLatitude() + ", " + hotel.getLongitude();
this.pic = hotel.getPic();
}
}
HotelService.java
?@Override
? ? public PageResult search(RequestParams params) {
? ? ? ? try {
? ? ? ? ? ? //1、准备Request
? ? ? ? ? ? SearchRequest request = new SearchRequest("hotel");
? ? ? ? ? ? //2、准备DSL
? ? ? ? ? ? //2.1、query
? ? ? ? ? ? buildBasicQuery(params,request);
? ? ? ? ? ? //2.2、分页
? ? ? ? ? ? int page = params.getPage();
? ? ? ? ? ? int size = params.getSize();
? ? ? ? ? ? request.source().from((page - 1) * size).size(size);
? ? ? ? ? ? //2.3、排序
? ? ? ? ? ? String location = params.getLocation();
? ? ? ? ? ? if(location != null && !"".equals(location)){
? ? ? ? ? ? ? ? request.source().sort(SortBuilders
? ? ? ? ? ? ? ? ? ? ? ? .geoDistanceSort("location",new GeoPoint(location))
? ? ? ? ? ? ? ? ? ? ? ? .order(SortOrder.ASC)
? ? ? ? ? ? ? ? ? ? ? ? .unit(DistanceUnit.KILOMETERS)
? ? ? ? ? ? ? ? );
? ? ? ? ? ? }
? ? ? ? ? ? //3、发送请求
? ? ? ? ? ? SearchResponse response = client.search(request, RequestOptions.DEFAULT);
? ? ? ? ? ? //4、解析响应
? ? ? ? ? ? return handleResponse(response);
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? throw new RuntimeException(e);
? ? ? ? }
? ? }? ? private void buildBasicQuery(RequestParams params, SearchRequest request) {
? ? ? ? //构建BooleanQuery
? ? ? ? BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
? ? ? ? //关键字搜索
? ? ? ? String key = params.getKey();
? ? ? ? if(key == null || "".equals(key)){
? ? ? ? ? ? boolQuery.must(QueryBuilders.matchAllQuery());
? ? ? ? }else{
? ? ? ? ? ? boolQuery.must(QueryBuilders.matchQuery("all",key));
? ? ? ? }
? ? ? ? //城市条件
? ? ? ? if(params.getCity() != null && !"".equals(params.getCity())){
? ? ? ? ? ? boolQuery.filter(QueryBuilders.termQuery("city", params.getCity()));
? ? ? ? }
? ? ? ? //品牌条件
? ? ? ? if(params.getBrand() != null && !"".equals(params.getBrand())){
? ? ? ? ? ? boolQuery.filter(QueryBuilders.termQuery("brand", params.getBrand()));
? ? ? ? }
? ? ? ? //星级条件
? ? ? ? if(params.getStarName() != null && !"".equals(params.getStarName())){
? ? ? ? ? ? boolQuery.filter(QueryBuilders.termQuery("starName", params.getStarName()));
? ? ? ? }
? ? ? ? //价格
? ? ? ? if(params.getMinPrice() != null && params.getMaxPrice() != null){
? ? ? ? ? ? boolQuery.filter(QueryBuilders.rangeQuery("price").gte(params.getMinPrice()).lte(params.getMaxPrice()));
? ? ? ? }? ? ? ? request.source().query(functionScoreQueryBuilder);
? ? }? ? private PageResult handleResponse(SearchResponse response) {
? ? ? ? //4、解析响应
? ? ? ? SearchHits searchHits = response.getHits();
? ? ? ? //4.1获取总条数
? ? ? ? long total = searchHits.getTotalHits().value;
? ? ? ? //4.2文档数组
? ? ? ? SearchHit[] hits = searchHits.getHits();
? ? ? ? //4.3遍历
? ? ? ? List<HotelDoc> hotels = new ArrayList<>();
? ? ? ? for (SearchHit hit : hits) {
? ? ? ? ? ? //获取文档source
? ? ? ? ? ? String json = hit.getSourceAsString();
? ? ? ? ? ? //反序列化
? ? ? ? ? ? HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
? ? ? ? ? ? //获取距离
? ? ? ? ? ? Object[] sortValues = hit.getSortValues();
? ? ? ? ? ? if(sortValues.length > 0){
? ? ? ? ? ? ? ? Object sortValue = sortValues[0];
? ? ? ? ? ? ? ? hotelDoc.setDistance(sortValue);
? ? ? ? ? ? }
? ? ? ? ? ? hotels.add(hotelDoc);
? ? ? ? }
? ? ? ? //4、封装返回
? ? ? ? return new PageResult(total,hotels);
? ? }
?
package cn.itcast.hotel.service.impl;
import cn.itcast.hotel.mapper.HotelMapper;
import cn.itcast.hotel.pojo.Hotel;
import cn.itcast.hotel.pojo.HotelDoc;
import cn.itcast.hotel.pojo.PageResult;
import cn.itcast.hotel.pojo.RequestParams;
import cn.itcast.hotel.service.IHotelService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.lucene.queries.function.FunctionScoreQuery;
import org.apache.lucene.search.vectorhighlight.ScoreOrderFragmentsBuilder;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
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.common.geo.GeoPoint;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.SuggestBuilders;
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class HotelService extends ServiceImpl<HotelMapper, Hotel> implements IHotelService {
@Autowired
private RestHighLevelClient client;
@Override
public PageResult search(RequestParams params) {
try {
//1、准备Request
SearchRequest request = new SearchRequest("hotel");
//2、准备DSL
//2.1、query
buildBasicQuery(params,request);
//2.2、分页
int page = params.getPage();
int size = params.getSize();
request.source().from((page - 1) * size).size(size);
//2.3、排序
String location = params.getLocation();
if(location != null && !"".equals(location)){
request.source().sort(SortBuilders
.geoDistanceSort("location",new GeoPoint(location))
.order(SortOrder.ASC)
.unit(DistanceUnit.KILOMETERS)
);
}
//3、发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//4、解析响应
return handleResponse(response);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private void buildBasicQuery(RequestParams params, SearchRequest request) {
//构建BooleanQuery
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
//关键字搜索
String key = params.getKey();
if(key == null || "".equals(key)){
boolQuery.must(QueryBuilders.matchAllQuery());
}else{
boolQuery.must(QueryBuilders.matchQuery("all",key));
}
//城市条件
if(params.getCity() != null && !"".equals(params.getCity())){
boolQuery.filter(QueryBuilders.termQuery("city", params.getCity()));
}
//品牌条件
if(params.getBrand() != null && !"".equals(params.getBrand())){
boolQuery.filter(QueryBuilders.termQuery("brand", params.getBrand()));
}
//星级条件
if(params.getStarName() != null && !"".equals(params.getStarName())){
boolQuery.filter(QueryBuilders.termQuery("starName", params.getStarName()));
}
//价格
if(params.getMinPrice() != null && params.getMaxPrice() != null){
boolQuery.filter(QueryBuilders.rangeQuery("price").gte(params.getMinPrice()).lte(params.getMaxPrice()));
}
request.source().query(functionScoreQueryBuilder);
}
private PageResult handleResponse(SearchResponse response) {
//4、解析响应
SearchHits searchHits = response.getHits();
//4.1获取总条数
long total = searchHits.getTotalHits().value;
//4.2文档数组
SearchHit[] hits = searchHits.getHits();
//4.3遍历
List<HotelDoc> hotels = new ArrayList<>();
for (SearchHit hit : hits) {
//获取文档source
String json = hit.getSourceAsString();
//反序列化
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
//获取距离
Object[] sortValues = hit.getSortValues();
if(sortValues.length > 0){
Object sortValue = sortValues[0];
hotelDoc.setDistance(sortValue);
}
hotels.add(hotelDoc);
}
//4、封装返回
return new PageResult(total,hotels);
}
}
此时可以看到距离
?
RequestParams.java
package cn.itcast.hotel.pojo;
import lombok.Data;
@Data
public class RequestParams {
private String key;
private Integer page;
private Integer size;
private String sortBy;
private String city;
private String brand;
private String starName;
private Integer minPrice;
private Integer maxPrice;
private String location;
}
HotelDoc.java
package cn.itcast.hotel.pojo;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.*;
@Data
@NoArgsConstructor
public class HotelDoc {
private Long id;
private String name;
private String address;
private Integer price;
private Integer score;
private String brand;
private String city;
private String starName;
private String business;
private String location;
private String pic;
private Object distance;
private Boolean isAD;
private List<String> suggestion;
public HotelDoc(Hotel hotel) {
this.id = hotel.getId();
this.name = hotel.getName();
this.address = hotel.getAddress();
this.price = hotel.getPrice();
this.score = hotel.getScore();
this.brand = hotel.getBrand();
this.city = hotel.getCity();
this.starName = hotel.getStarName();
this.business = hotel.getBusiness();
this.location = hotel.getLatitude() + ", " + hotel.getLongitude();
this.pic = hotel.getPic();
}
}
HotelService.java
package cn.itcast.hotel.service.impl;
import cn.itcast.hotel.mapper.HotelMapper;
import cn.itcast.hotel.pojo.Hotel;
import cn.itcast.hotel.pojo.HotelDoc;
import cn.itcast.hotel.pojo.PageResult;
import cn.itcast.hotel.pojo.RequestParams;
import cn.itcast.hotel.service.IHotelService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.lucene.queries.function.FunctionScoreQuery;
import org.apache.lucene.search.vectorhighlight.ScoreOrderFragmentsBuilder;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
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.common.geo.GeoPoint;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.SuggestBuilders;
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class HotelService extends ServiceImpl<HotelMapper, Hotel> implements IHotelService {
@Autowired
private RestHighLevelClient client;
@Override
public PageResult search(RequestParams params) {
try {
//1、准备Request
SearchRequest request = new SearchRequest("hotel");
//2、准备DSL
//2.1、query
buildBasicQuery(params,request);
//2.2、分页
int page = params.getPage();
int size = params.getSize();
request.source().from((page - 1) * size).size(size);
//2.3、排序
String location = params.getLocation();
if(location != null && !"".equals(location)){
request.source().sort(SortBuilders
.geoDistanceSort("location",new GeoPoint(location))
.order(SortOrder.ASC)
.unit(DistanceUnit.KILOMETERS)
);
}
//3、发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//4、解析响应
return handleResponse(response);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private void buildBasicQuery(RequestParams params, SearchRequest request) {
//构建BooleanQuery
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
//关键字搜索
String key = params.getKey();
if(key == null || "".equals(key)){
boolQuery.must(QueryBuilders.matchAllQuery());
}else{
boolQuery.must(QueryBuilders.matchQuery("all",key));
}
//城市条件
if(params.getCity() != null && !"".equals(params.getCity())){
boolQuery.filter(QueryBuilders.termQuery("city", params.getCity()));
}
//品牌条件
if(params.getBrand() != null && !"".equals(params.getBrand())){
boolQuery.filter(QueryBuilders.termQuery("brand", params.getBrand()));
}
//星级条件
if(params.getStarName() != null && !"".equals(params.getStarName())){
boolQuery.filter(QueryBuilders.termQuery("starName", params.getStarName()));
}
//价格
if(params.getMinPrice() != null && params.getMaxPrice() != null){
boolQuery.filter(QueryBuilders.rangeQuery("price").gte(params.getMinPrice()).lte(params.getMaxPrice()));
}
request.source().query(functionScoreQueryBuilder);
}
private PageResult handleResponse(SearchResponse response) {
//4、解析响应
SearchHits searchHits = response.getHits();
//4.1获取总条数
long total = searchHits.getTotalHits().value;
//4.2文档数组
SearchHit[] hits = searchHits.getHits();
//4.3遍历
List<HotelDoc> hotels = new ArrayList<>();
for (SearchHit hit : hits) {
//获取文档source
String json = hit.getSourceAsString();
//反序列化
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
//获取距离
Object[] sortValues = hit.getSortValues();
if(sortValues.length > 0){
Object sortValue = sortValues[0];
hotelDoc.setDistance(sortValue);
}
hotels.add(hotelDoc);
}
//4、封装返回
return new PageResult(total,hotels);
}
}
此时优先显示近的周边
?
代码文件点击下载https://pan.baidu.com/s/1e_aKaZ8Qvo1GG3nbFe97zQ?pwd=81s2?上一篇:ES的安装和RestClient的操作