微服务-ES高级查询和案例
Day06- ES高级查询和案例
本章小结:
同步
- i
[TOC]
No.01-ES高级查询
1、全部查询
# 全部查询(默认前十条)
GET /hotel/_search
{
"query": {
"match_all": {}
}
}
2、全文搜索
# 单字段全文搜索(分词倒排索引,但是用到了多字段聚合)
GET /hotel/_search
{
"query": {
"match": {
"all": "外滩如家"
}
}
}
# 多字段全文检索(性能低下,可以的话提前做聚合)
GET /hotel/_search
{
"query": {
"multi_match": {
"query": "外滩如家",
"fields": ["brand", "business", "name"]
}
}
}
3、精确匹配
# 精确匹配
GET /hotel/_search
{
"query": {
"term": {
"city": {
"value": "北京"
}
}
}
}
4、范围查询(数字、日期?)
# range范围查询
GET /hotel/_search
{
"query": {
"range": {
"price": {
"gte": 3000,
"lte": 5000
}
}
}
}
5、地理查询(矩形、半径)
# 地理坐标矩形查询 geo_bounding_box查询
GET /hotel/_search
{
"query": {
"geo_bounding_box": {
"location": {
"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": "15km",
"location": "31.21,121.5"
}
}
}
6、算法函数查询
# 算法函数查询
GET /hotel/_search
{
"query": {
"function_score": {
"query": {
"match": {
"all": "外滩如家"
}
},
"functions": [
{
"filter": {
"term": {
"brand": "君悦"
}
},
"weight": 2
}
],
"boost_mode": "multiply"
}
}
}
7、组合查询
# 布尔组合查询,must_not,filter不算法性能高,推荐
GET /hotel/_search
{
"query": {
"bool": {
"must": [
{"term": {"city": "上海" }},
{"match": {"starName": "五钻"}}
],
"should": [
{"term": {"brand": "皇冠假日" }},
{"term": {"brand": "华美达" }}
],
"must_not": [
{ "range": { "price": { "lte": 500 } }}
],
"filter": [
{ "range": {"score": { "lte": 45 } }}
]
}
}
}
No.02-ES搜索结果处理
1、一般排序
# 一般排序
GET /hotel/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"score": "desc"
},
{
"price": "asc"
}
]
}
2、地理排序
# 经纬度排序
GET /hotel/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"_geo_distance" : {
"location" : "30.9, 121.7",
"order" : "asc",
"unit" : "km"
}
}
]
}
3、分页
分页默认1万条,超出要么改配置,要么用search after后翻页、scroll快照,但都有缺陷和性能浪费,一般从业务层面控制
百度、京东也是限制一千条、百页左右的而已
# 分页
GET /hotel/_search
{
"query": {
"match_all": {}
},
"from": 0,
"size": 10,
"sort": [
{"price": "asc"}
]
}
4、高亮
# 高亮
GET /hotel/_search
{
"query": {
"match": {
"name": "如家"
}
},
"highlight": {
"fields": {
"name": {
"pre_tags": "<em>",
"post_tags": "</em>",
"require_field_match": "false"
}
}
}
}
No.03-RestClient编程
地理位置查询的实现采用后过滤的方案,==算法函数查询没有实现==
@Test
void testQueryFunctionScore() {}
官方文档☞地理位置查询
1、查询
package com.iyyxx.hotel;
import com.alibaba.fastjson.JSON;
import com.iyyxx.hotel.pojo.HotelDoc;
import com.iyyxx.hotel.service.IHotelService;
import org.apache.http.HttpHost;
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.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.util.CollectionUtils;
import java.io.IOException;
import java.util.Map;
@SpringBootTest
public class HotelSearchTest {
@Autowired private IHotelService service;
private RestHighLevelClient client;
@BeforeEach
void setUp() {
client =
new RestHighLevelClient(RestClient.builder(HttpHost.create("http://192.168.20.165:9200")));
}
@AfterEach
void tearDown() throws IOException {
this.client.close();
}
private void handleResponse(SearchResponse response) {
SearchHits searchHits = response.getHits();
long total = searchHits.getTotalHits().value;
System.out.println("查询到总条数:"+total);
System.out.println("实际条数:"+searchHits.getHits().length);
SearchHit[] hits = searchHits.getHits();
for (SearchHit hit : hits) {
String json = hit.getSourceAsString();
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
System.out.println(hotelDoc);
}
}
@Test
void testQueryMatchALl() throws IOException {
SearchRequest request = new SearchRequest("hotel");
// 全表扫描,但默认只范围前十条
request.source().query(QueryBuilders.matchAllQuery());
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
handleResponse(response);
}
@Test
void testQueryMatch() throws IOException {
SearchRequest request = new SearchRequest("hotel");
// 单字段匹配,但是all其实有4,5个字段的提前聚合,具体可以 GET /hotel 查看
request.source().query(QueryBuilders.matchQuery("all", "外滩如家"));
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
handleResponse(response);
}
@Test
void testQueryMulthiMatch() throws IOException {
SearchRequest request = new SearchRequest("hotel");
// 多字段匹配“外滩如家”,按品牌、商业圈、名称
request.source().query(QueryBuilders.multiMatchQuery("外滩如家", "brand", "business", "name"));
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
handleResponse(response);
}
@Test
void testQueryTerm() throws IOException {
SearchRequest request = new SearchRequest("hotel");
// 精确查询位于北京城的酒店
request.source().query(QueryBuilders.termQuery("city", "北京"));
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
handleResponse(response);
}
@Test
void testQueryRang() throws IOException {
SearchRequest request = new SearchRequest("hotel");
// 查询价格大于300,小于500的酒店
request.source().query(QueryBuilders.rangeQuery("price").gte(300).lte(500));
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
handleResponse(response);
}
@Test
void testQueryBool() throws IOException {
SearchRequest request = new SearchRequest("hotel");
// 上海市、五钻、品牌(皇冠假日、华美达)、价格不低于500,评分大于4.5
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
boolQuery.must(QueryBuilders.termQuery("city","上海"));
boolQuery.must(QueryBuilders.termQuery("starName","五钻"));
boolQuery.should(QueryBuilders.termQuery("brand","皇冠假日"));
boolQuery.should(QueryBuilders.termQuery("brand","华美达"));
boolQuery.mustNot(QueryBuilders.rangeQuery("price").lt(500));
boolQuery.filter(QueryBuilders.rangeQuery("score").lt(45));
request.source().query(boolQuery);
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
handleResponse(response);
}
@Test
void testQueryGeoBox() throws IOException {
SearchRequest request = new SearchRequest("hotel");
request.source().query(QueryBuilders.matchAllQuery());
// Using pre-indexed shapes
request
.source()
.postFilter(
QueryBuilders.geoBoundingBoxQuery("location").setCorners(31.1, 121.5, 30.9, 121.7));
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
handleResponse(response);
}
@Test
void testQueryGeoDistance() throws IOException {
SearchRequest request = new SearchRequest("hotel");
request.source().query(QueryBuilders.matchAllQuery());
request
.source()
.postFilter(
QueryBuilders.geoDistanceQuery("location")
.point(31.21, 121.5)
.distance(15, DistanceUnit.KILOMETERS));
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
handleResponse(response);
}
}
2、搜索结果处理(排序、分页、过滤、高亮等)
高亮部分的数据是另外组织,需要使用时得单独拿出来,然后做替换!
package com.iyyxx.hotel;
import com.alibaba.fastjson.JSON;
import com.iyyxx.hotel.pojo.HotelDoc;
import com.iyyxx.hotel.service.IHotelService;
import org.apache.http.HttpHost;
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.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.util.CollectionUtils;
import java.io.IOException;
import java.util.Map;
@SpringBootTest
public class HotelSearchTest {
@Autowired private IHotelService service;
private RestHighLevelClient client;
@BeforeEach
void setUp() {
client =
new RestHighLevelClient(RestClient.builder(HttpHost.create("http://192.168.20.165:9200")));
}
@AfterEach
void tearDown() throws IOException {
this.client.close();
}
private void handleResponse(SearchResponse response) {
SearchHits searchHits = response.getHits();
long total = searchHits.getTotalHits().value;
System.out.println("查询到总条数:"+total);
System.out.println("实际条数:"+searchHits.getHits().length);
SearchHit[] hits = searchHits.getHits();
for (SearchHit hit : hits) {
String json = hit.getSourceAsString();
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
// 高亮处理,取出name再塞回去。。。
Map<String, HighlightField> highlightFieldMap = hit.getHi
ghlightFields();
if(!CollectionUtils.isEmpty(highlightFieldMap)){
HighlightField highlightField = highlightFieldMap.get("name");
if(highlightField!=null){
String name = highlightField.getFragments()[0].string();
hotelDoc.setName(name);
}
}
System.out.println(hotelDoc);
}
}
@Test
void testPageAndSor() throws IOException {
SearchRequest request = new SearchRequest("hotel");
// 全表扫描
request.source().query(QueryBuilders.matchAllQuery());
// 排序,按价格从高到底
request.source().sort("score", SortOrder.DESC);
request.source().sort("price", SortOrder.ASC);
// 分页,从0开始,50条一页
request.source().from(0).size(50);
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
handleResponse(response);
}
@Test
void testHighLight() throws IOException {
SearchRequest request = new SearchRequest("hotel");
request.source().query(QueryBuilders.matchQuery("all", "如家"));
// 全表扫描,对名称字段里的关键字进行高亮,并从10条开始取11条,突破默认0-10
request.source().highlighter(new HighlightBuilder().field("name").requireFieldMatch(false));
request.source().from(11).size(11);
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
handleResponse(response);
}
}
评论系统未开启,无法评论!