一、DSL查詢(xún)文檔
(一)DSL查詢(xún)分類(lèi)
ES提供了基于JSON的DSL來(lái)定義查詢(xún)。
1、常見(jiàn)查詢(xún)類(lèi)型:
- 查詢(xún)所有: 查詢(xún)出所有的數(shù)據(jù),例如,match_all
-
全文檢索(full text)查詢(xún): 利用分詞器對(duì)用戶(hù)輸入內(nèi)容分詞,然后去倒排索引庫(kù)中匹配。例如:
- match_query
- multi_match_query
-
精確查詢(xún): 根據(jù)精確詞條值查找數(shù)據(jù),一般查找精確值,例如:
- ids
- range
- term
-
地理(geo)坐標(biāo)查詢(xún): 根據(jù)經(jīng)緯度查詢(xún),例如:
- geo_distance
- geo_bounding_box
-
復(fù)合(compound)查詢(xún): 復(fù)合查詢(xún)可以將傷處查詢(xún)條件組合起來(lái),合并查詢(xún)條件,例如:
- bool
- function_score
2、查詢(xún)的基本語(yǔ)法
GET /indexName/_search
{
"query": {
"查詢(xún)類(lèi)型": {
"查詢(xún)條件": "條件值"
}
}
}
3、match_all的使用
GET /indexName/_search
{
"query": {
"match_all": { }
}
}
查詢(xún)效果
{
"took" : 446,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "test",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"info" : "這是我的ES拆分Demo",
"age" : 18,
"email" : "zengoo@163.com",
"name" : {
"firstName" : "Zengoo",
"lastName" : "En"
}
}
}
]
}
}
(二)全文檢索查詢(xún)
全文檢索查詢(xún),會(huì)對(duì)用戶(hù)輸入內(nèi)容分詞,常用于搜索框搜索。
1、match查詢(xún)
(1)結(jié)構(gòu)
GET /indexName/_search
{
"query": {
"match": {
"FILED": "TEXT"
}
}
}
(2)簡(jiǎn)單使用
GET /test/_search
{
"query": {
"match": {
"info": "ES" #當(dāng)有聯(lián)合屬性all,進(jìn)行匹配,就可以進(jìn)行多條件匹配,按照匹配數(shù)量來(lái)確定權(quán)值大小。
}
}
}
使用結(jié)果
{
"took" : 71,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.2876821,
"hits" : [
{
"_index" : "test",
"_type" : "_doc",
"_id" : "1",
"_score" : 0.2876821,
"_source" : {
"info" : "這是我的ES拆分Demo",
"age" : 18,
"email" : "zengoo@163.com",
"name" : {
"firstName" : "Zengoo",
"lastName" : "En"
}
}
}
]
}
}
2、multi_match查詢(xún)
從使用效果上,與條件查詢(xún)的"all"字段相同。
(1)結(jié)構(gòu)
GET /indexName/_search
{
"query": {
"multi_match": {
"query": "TEXT",
"fields": ["FIELD1", "FIELD2"]
}
}
}
(2)簡(jiǎn)單使用
GET /test/_search
{
"query": {
"multi_match": {
"query": "ES",
"fields": ["info","age"]
}
}
}
(三)精準(zhǔn)查詢(xún)
精確查詢(xún)一般是查找精確值,所以不會(huì)對(duì)搜索條件分詞。
1、term: 根據(jù)詞條精確值查詢(xún),在商城項(xiàng)目中,通常會(huì)用在類(lèi)型篩選上。
(1)結(jié)構(gòu)
GET /test/_search
{
"query": {
"term": {
"FIELD": {
"value": "VALUE"
}
}
}
}
(2)簡(jiǎn)單使用
GET /test/_search
{
"query": {
"term": {
"city": {
"value": "杭州" #精確值
}
}
}
}
2、range: 根據(jù)值范圍查詢(xún),在商城項(xiàng)目中,通常會(huì)用在價(jià)值篩選上。
(1)結(jié)構(gòu)
GET /test/_search
{
"query": {
"range": {
"FIELD": {
"gte": 10,
"lte": 20
}
}
}
}
(2)簡(jiǎn)單使用
GET /test/_search
{
"query": {
"range": {
"price": {
"gte": 699, #最低值,gte 大于等于,gt 大于
"lte": 1899 #最高值,lte 小于等于,lt 小于
}
}
}
}
(四)地理坐標(biāo)查詢(xún)
1、geo_distance: 查詢(xún)到指定中心小于某個(gè)距離值的所有文檔(圓形范圍圈)。
(1)結(jié)構(gòu)
GET /indexName/_search
{
"query": {
"geo_distance": {
"distance": "15km",
"FIELD": "13.21,121.5"
}
}
}
(2)簡(jiǎn)單使用
GET /test/_search
{
"query": {
"geo_distance": {
"distance": "20km",
"location": "13.21,121.5"
}
}
}
2、geo_bounding_box: 查詢(xún)geo_point值落在某個(gè)舉行范圍的所有文檔(矩形范圍圈)。
(1)結(jié)構(gòu)
GET /indexName/_search
{
"query": {
"geo_bounding_box": {
"FIELD": {
"top_left": {
"lat": 31.1,
"lon": 121.5
},
"bottom_right": {
"lat": 30.9,
"lon": 121.7
}
}
}
}
}
(五)復(fù)合查詢(xún)
復(fù)合查詢(xún)可以將其它簡(jiǎn)單查詢(xún)組合起來(lái),實(shí)現(xiàn)更復(fù)雜的搜索邏輯。
1、function score: 算分函數(shù)查詢(xún),可以控制文檔相關(guān)性算分,控制文檔排名。
當(dāng)我們利用match查詢(xún)時(shí),文檔結(jié)果會(huì)根據(jù)搜索詞條的關(guān)聯(lián)度打分(_score),返回結(jié)果時(shí)按照分值降序排列。
例如,在搜索CSDNJava。
[
{
"_score": 17.85048,
"_source": {
"name": "Java語(yǔ)法菜鳥(niǎo)教程"
}
},
{
"_score": 12.587963,
"_source": {
"name": "Java語(yǔ)法W3CScool"
}
},
{
"_score": 11.158756,
"_source": {
"name": "CSDNJava語(yǔ)法學(xué)習(xí)樹(shù)"
}
},
]
相關(guān)算法:
- 最開(kāi)始的算分算法:TF(詞條頻率) = 詞條 / 文檔詞條總數(shù)
-
避免公共詞條改良的算分算法:TF-IDF算法
- IDF(逆文檔頻率) = Log( 文檔總數(shù) / 包含詞條的文檔總數(shù) )
- socre = (∑(i,n) TF) * IDF
- BM25算法: 現(xiàn)在默認(rèn)采用的算法,該算法比較復(fù)雜,其詞頻曲度最終會(huì)趨于水平。
(1)結(jié)構(gòu)
GET /hotel/_search
{
"query": {
"function_socre": { #查詢(xún)類(lèi)型
"query": { #查詢(xún)?cè)紨?shù)據(jù)
"match": {
"all": "外灘"
}
},
"functions": [ #解析方法
{
"filter": { # 過(guò)濾條件
"term": {
"id": "1"
}
},
"weight": 10 # score算分方法,weight是直接以常量為函數(shù)結(jié)果,其它的還有feild_value_factor:以某字段作為函數(shù)結(jié)果,random_score: 隨機(jī)值作為函數(shù)結(jié)果,script_score:定義計(jì)算公式
}
],
"boost_mode": "multiply" # 加權(quán)模式,定義function score 與 query score的運(yùn)算方式,包括 multiply:兩者相乘(默認(rèn));replace:用function score 替換 query score;其它: sum、avg、max、min
}
}
}
(2)簡(jiǎn)單使用
需求: 將用戶(hù)給的詞條排名靠前
需要考慮的元素:
- 哪些文檔需要算分加權(quán) : 包含詞條內(nèi)容的文檔
- 算分函數(shù)是什么: weight
- 加權(quán)模式用哪個(gè): sum
實(shí)現(xiàn):
GET /hotel/_search
{
"query": {
"function_socre": { # 算分算法
"query": {
"match": {
"all": "速8快捷酒店"
}
},
"functions": [
{
"filter": { # 滿(mǎn)足條件,品牌必須是速8
"term": {
"brand": "速8"
}
},
"weight": 2 #算分權(quán)重為 2
}
],
"boost_mode": "sum"
}
}
}
2、復(fù)合查詢(xún) Boolean Query
子查詢(xún)的組合方式:
- must: 必須匹配每個(gè)子查詢(xún),類(lèi)似 “與”
- should: 選擇性匹配子查詢(xún),類(lèi)似 “或”
- must_not: 排除匹配模式,不參與算分,類(lèi)似 “非”
- filter: 必須匹配,不參與算分
實(shí)現(xiàn)案例
#搜查位置位于上海,品牌為“皇冠假日”或是“華美達(dá)”,并且價(jià)格500<price<600元,且評(píng)分大于等于45的酒店
GET /hotel/_search
{
"query": {
"bool": {
"must": [ # 必須匹配的條件
{ "term": { "city: "上海" } }
],
"should": [ # 可以匹配到條件
{ "term": { "brand": "皇冠假日" } },
{ "term": { "brand": "華美達(dá)" } }
],
"must_not": [ #不匹配的條件
{ "range": { "price": {"lte": 500, "gte": 600} }}
],
"filter": [ #篩選條件
{ "range": { "score": { "gte": 45 } } }
]
}
}
}
二、搜索結(jié)果處理
(一)排序
ES支持對(duì)搜索結(jié)果排序,默認(rèn)根據(jù)(_score)來(lái)排序,可以排序的字段類(lèi)型有:keyword、數(shù)值類(lèi)型、地理坐標(biāo)類(lèi)型、日期類(lèi)型等
1、結(jié)構(gòu):
# 普通類(lèi)型排序
GET /test/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"FIELD": {
"order": "desc" # 排序字段和排序方式ASC、DESC
}
}
]
}
# 地理坐標(biāo)型排序
GET /test/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"_geo_distance": {
"FIELD": { #精度維度
"lat": 40,
"lon": -70
},
"order": "asc",
"unit": "km"
}
}
]
}
2、實(shí)現(xiàn)案例
排序需求: 按照用戶(hù)評(píng)價(jià)降序,評(píng)價(jià)相同的按照價(jià)格升序。
GET /hotel/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"score": { # 簡(jiǎn)化結(jié)構(gòu)可以使用,"score": "desc"
"order": "desc"
},
"price": {
"order": "asc"
}
}
]
}
排序需求: 按照距離用戶(hù)位置的距離進(jìn)行升序。
GET /hotel/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"_geo_distance": {
"location": {
"lat": 40.58489,
"lon": -70.59873
},
"order": "asc",
"unit": "km"
}
}
]
}
(二)分頁(yè)
修改分頁(yè)參數(shù)
GET /hotel/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"price": "asc"
}
],
"from": 100, # 分頁(yè)開(kāi)始的位置,默認(rèn)為0
"size": 20, # 期望獲取的文檔總數(shù)
}
深度分頁(yè)問(wèn)題
當(dāng)我們將ES做成一個(gè)集群服務(wù),那么我們需要選擇前10的數(shù)據(jù)時(shí),ES底層會(huì)如何去實(shí)現(xiàn)呢?
ES由于使用的是倒排索引,每一臺(tái)ES都會(huì)分片數(shù)據(jù)。
1、每個(gè)數(shù)據(jù)分片上都排序并查詢(xún)前1000條文檔。
2、聚合所有節(jié)點(diǎn)的結(jié)果,在內(nèi)存中重新排序選出前1000條文檔。
3、從前1000挑中,選取from=990,size=10的文檔
如果搜索頁(yè)數(shù)過(guò)深,或者結(jié)果集過(guò)大,對(duì)內(nèi)存和CPU的消耗越高,因此ES設(shè)置的結(jié)果集查詢(xún)上限是10000條。
如何解決深度分頁(yè)的問(wèn)題?
- seach after: 分頁(yè)時(shí)需要排序,原理是從上一次的排序值開(kāi)始,查詢(xún)下一頁(yè)數(shù)據(jù)(官方推薦)。
- scroll: 原理是將排序數(shù)據(jù)形成緩存保存在內(nèi)存(官方不推薦)。
(三)高亮
1、概念: 在搜索結(jié)果中搜索關(guān)鍵字突出顯示。
2、原理
- 將搜索結(jié)果中的關(guān)鍵字用標(biāo)簽標(biāo)記出來(lái)
- 在頁(yè)面中給標(biāo)簽添加css樣式
3、語(yǔ)法:
GET /indexName/_search
{
"query": {
"match": {
"FIELD": "TEXT"
}
},
"highlight": { #高亮字段
"fields": {
"FIELD": {
"pre_tags": "<em>", #標(biāo)簽前綴
"post_tags": "</em>", #標(biāo)簽后綴
"require_field_match": "false" #判斷該字段是否與前面查詢(xún)的字段匹配
}
}
}
}
三、RestClient查詢(xún)文檔
(一)實(shí)現(xiàn)簡(jiǎn)單查詢(xún)案例
//1、準(zhǔn)備Request
SearchRequest request = new SearchRequest("hotel");
//2、組織DSL參數(shù),QueryBuilders是ES的查詢(xún)API庫(kù)
request.source().query(QueryBuilders.matchAllQuery());
//3、發(fā)送請(qǐng)求,得到響應(yīng)結(jié)果
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//4、解析響應(yīng)結(jié)果,搜索結(jié)果會(huì)放置在Hits集合中
SearchHits searchHits = response.getHits();
//5、查詢(xún)總數(shù)
long total = searchHits.getTotalHits().value;
//6、查詢(xún)的結(jié)果數(shù)組
SearchHit[] hits = searchHits.getHits();
for(SearchHit hit: hits) {
//得到source,source就是查詢(xún)出來(lái)的實(shí)體信息
String json = hit.getSourceAsString();
//序列化
HotelDoc hotelDoc = JSON.parseObject(json,HotelDoc.class);
}
(二)match查詢(xún)
//1、準(zhǔn)備Request
SearchRequest request = new SearchRequest("hotel");
//2、組織DSL參數(shù),QueryBuilders是ES的查詢(xún)API庫(kù)
//單字段查詢(xún)
request.source().query(QueryBuilders.matchQuery("all","皇家"));
//多字段查詢(xún)
//request.source().query(QueryBuilders.multiMatchQuery("皇家","name","buisiness"));
//3、發(fā)送請(qǐng)求,得到響應(yīng)結(jié)果
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//4、解析響應(yīng)結(jié)果,搜索結(jié)果會(huì)放置在Hits集合中
SearchHits searchHits = response.getHits();
//5、查詢(xún)總數(shù)
long total = searchHits.getTotalHits().value;
//6、查詢(xún)的結(jié)果數(shù)組
SearchHit[] hits = searchHits.getHits();
for(SearchHit hit: hits) {
//得到source,source就是查詢(xún)出來(lái)的實(shí)體信息
String json = hit.getSourceAsString();
//序列化
HotelDoc hotelDoc = JSON.parseObject(json,HotelDoc.class);
}
(三)精確查詢(xún)
//詞條查詢(xún)
QueryBuilders.termQuery("city","杭州");
//范圍查詢(xún)
QueryBuilders.rangeQuery("price").gte(100).lte(150);
(四)復(fù)合查詢(xún)
//創(chuàng)建布爾查詢(xún)
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
//添加must條件
boolQuery.must(QueryBuilders.termQuery("city","杭州"));
//添加filter條件
boolQuery.filter(QueryBuilders.rangeQuery("price").lte(250));
(五)排序、分頁(yè)、高亮
1、排序與分頁(yè)
// 查詢(xún)
request.source().query(QueryBuilders.matchAllQuery());
// 分頁(yè)配置
request.source().from(0).size(5);
// 價(jià)格排序
request.source().sort("price", SortOrder.ASC);
2、高亮
高亮查詢(xún)請(qǐng)求文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-604513.html
request.source().highlighter(new HighLightBuilder().field("name").requireFieldMatch(false));
處理高亮結(jié)果文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-604513.html
// 獲取source
HotelDoc hotelDoc = JSON.parseObject(hit.getSourceAsString(), HotelDoc.class);
// 處理高亮
Map<String, HighlightFields> highlightFields = hit.getHighlightFields();
if(!CollectionUtils.isEmpty(highlightFields)) {
// 獲取字段結(jié)果
HighlightField highlightField = highlightFields.get("name");
if (highlightField != null) {
// 去除高亮結(jié)果數(shù)組的第一個(gè)
String name = highlightField.getFragments()[0].string();
hotelDoc.setName(name);
}
}
到了這里,關(guān)于SpringCloud學(xué)習(xí)路線(xiàn)(11)——分布式搜索ElasticSeach場(chǎng)景使用的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!