Elasticsearch学习4《Elasticsearch的各种查询》
文章目錄
- 一、term 和terms 查詢
- 1、term 查詢
- 2、terms查詢
- 二、 match查詢
- 1、math_all
- 2、match 查詢
- 3、布爾match 查詢
- 4、multi_match
- 三、其他查詢
- 1、id 查詢
- 2、ids查詢
- 3、prefix 查詢
- 4、 fuzzy 查詢
- 5、wildcard 查詢
- 6、rang 查詢
- 8、 regexp 查詢
- 四、深分頁 scroll
- 五、delete-by-query
- 六、復合查詢
- boosting 查詢
- 七、filter 查詢
- 八、高亮查詢
- 九、聚合查詢
- 1、去重計數聚合查詢
- 2、范圍統計
- 3、統計聚合
- 4、其他聚合查詢 查看官方文檔
- 十、 地圖經緯度搜索
- 1、ES 的地圖檢索方式
- 2、基于RESTFul 實現地圖檢索
- 3、 java 實現 geo_polygon
一、term 和terms 查詢
1、term 查詢
term 查詢是代表完全匹配,搜索之前不會對你搜索的關鍵字進行分詞,直接拿 關鍵字 去文檔分詞庫中匹配內容 #term查詢 POST /sms-logs-index/sms-logs-type/_search {#limit ?"from": 0, #limit x,?"size":5,"query": {"term": {"province": {"value": "北京"}}} } public class TermSearch {ObjectMapper mapper = new ObjectMapper();RestHighLevelClient client = EsClient.getClient();String index = "sms-logs-index";String type="sms-logs-type";@Testpublic void termSearchTest() throws IOException {// 1.創建request對象SearchRequest request = new SearchRequest(index);request.types(type);// 2.創建查詢條件SearchSourceBuilder builder = new SearchSourceBuilder();builder.from(0);builder.size(5);builder.query(QueryBuilders.termQuery("province","北京"));request.source(builder);// 3.執行查詢SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.輸出查詢結果for (SearchHit hit : response.getHits().getHits()) {Map<String, Object> sourceAsMap = hit.getSourceAsMap();System.out.println(sourceAsMap);}} }2、terms查詢
- terms 和 term 查詢的機制一樣,搜索之前不會對你搜索的關鍵字進行分詞,直接拿 關鍵字 去文檔分詞庫中匹配內容
- terms: 是針對一個字段包含多個值
- term : where province = 北京
- terms: where province = 北京 or province =? (類似于mysql 中的 in)
也可針對 text, 只是在分詞庫中查詢的時候不會進行分詞
二、 match查詢
match 查詢屬于高級查詢,會根據你查詢字段的類型不一樣,采用不同的查詢方式
- 查詢的是日期或者數值,他會將你基于字符串的查詢內容轉換為日期或數值對待
- 如果查詢的內容是一個不能被分詞的內容(keyword),match 不會將你指定的關鍵字進行分詞
- 如果查詢的內容是一個可以被分詞的內容(text),match 查詢會將你指定的內容根據一定的方式進行分詞,去分詞庫中匹配指定的內容
match 查詢,實際底層就是多個term 查詢,將多個term查詢的結果給你封裝到一起
1、math_all
查詢全部內容,不指定查詢條件
#match_all 查詢 POST /sms-logs-index/sms-logs-type/_search {"query":{"match_all": {}} } public class MatchSearch {ObjectMapper mapper = new ObjectMapper();RestHighLevelClient client = EsClient.getClient();String index = "sms-logs-index";String type="sms-logs-type";@Testpublic void matchAllSearch() throws IOException {// 1.創建request對象SearchRequest request = new SearchRequest(index);request.types(type);// 2.創建查詢條件SearchSourceBuilder builder = new SearchSourceBuilder();builder.query(QueryBuilders.matchAllQuery());// ES 默認只查詢10條數據builder.size(20);request.source(builder);// 3.執行查詢SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.輸出查詢結果for (SearchHit hit : response.getHits().getHits()) {System.out.println(hit.getSourceAsMap());}System.out.println(response.getHits().getHits().length);} }2、match 查詢
指定一個field 作為查詢條件
#match 查詢 POST /sms-logs-index/sms-logs-type/_search {"query": {"match": {"smsContent": "偉大戰士"}} } public class MatchSearch {ObjectMapper mapper = new ObjectMapper();RestHighLevelClient client = EsClient.getClient();String index = "sms-logs-index";String type="sms-logs-type";@Testpublic void matchSearch() throws IOException {// 1.創建request對象SearchRequest request = new SearchRequest(index);request.types(type);// 2.創建查詢條件SearchSourceBuilder builder = new SearchSourceBuilder();//--------------------------------------------------------------builder.query(QueryBuilders.matchQuery("smsContent","偉大戰士"));//--------------------------------------------------------------builder.size(20);request.source(builder);// 3.執行查詢SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.輸出查詢結果for (SearchHit hit : response.getHits().getHits()) {System.out.println(hit.getSourceAsMap());}System.out.println(response.getHits().getHits().length);}}3、布爾match 查詢
基于一個field 匹配的內容,按照 and 或者or的方式連接
#布爾match查詢 POST /sms-logs-index/sms-logs-type/_search {"query": {"match": {"smsContent": {# 既包含 戰士 也包含 團隊"query": "戰士 團隊","operator": "and"}}} }#布爾match查詢 POST /sms-logs-index/sms-logs-type/_search {"query": {"match": {"smsContent": {# 既包含 戰士 或者 團隊"query": "戰士 團隊","operator": "or"}}} } @Testpublic void booleanMatchSearch() throws IOException {// 1.創建request對象SearchRequest request = new SearchRequest(index);request.types(type);// 2.創建查詢條件SearchSourceBuilder builder = new SearchSourceBuilder();//--------------------------------------------------------------builder.query(QueryBuilders.matchQuery("smsContent","戰士 團隊").operator(Operator.AND));//--------------------------------------------------------------builder.size(20);request.source(builder);// 3.執行查詢SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.輸出查詢結果for (SearchHit hit : response.getHits().getHits()) {System.out.println(hit.getSourceAsMap());}System.out.println(response.getHits().getHits().length);}4、multi_match
match 針對一個field 做檢索,multi_math 針對多個field 進行檢索,多個field對應一個文本。
#multi_math 查詢 POST /sms-logs-index/sms-logs-type/_search {"query":{"multi_match": {"query": "北京","fields": ["province","smsContent"]}} } public void multiMatchSearch() throws IOException {// 1.創建request對象SearchRequest request = new SearchRequest(index);request.types(type);// 2.創建查詢條件SearchSourceBuilder builder = new SearchSourceBuilder();//--------------------------------------------------------------builder.query(QueryBuilders.multiMatchQuery("北京","province","smsContent"));//--------------------------------------------------------------builder.size(20);request.source(builder);// 3.執行查詢SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.輸出查詢結果for (SearchHit hit : response.getHits().getHits()) {System.out.println(hit.getSourceAsMap());}System.out.println(response.getHits().getHits().length);}三、其他查詢
1、id 查詢
#id 查詢 GET /sms-logs-index/sms-logs-type/1 public class IdGetSearch {ObjectMapper mapper = new ObjectMapper();RestHighLevelClient client = EsClient.getClient();String index = "sms-logs-index";String type="sms-logs-type";@Testpublic void findById() throws IOException {// 創建GetRequest對象GetRequest request = new GetRequest(index,type,"1");// 執行查詢GetResponse response = client.get(request, RequestOptions.DEFAULT);// 輸出結果System.out.println(response.getSourceAsMap());} }2、ids查詢
根據多個id 查詢,類似 mysql 中的 where in (id1,id2…)
#ids 查詢 POST /sms-logs-index/sms-logs-type/_search {"query": {"ids": {"values": ["1","2","3"]}} } public void findByIds() throws IOException {// 創建request對象SearchRequest request = new SearchRequest(index);request.types(type);// 指定查詢條件SearchSourceBuilder builder = new SearchSourceBuilder();//--------------------------------------------------builder.query(QueryBuilders.idsQuery().addIds("1","2","3"));//------------------------------------------------------request.source(builder);// 執行SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 輸出結果for (SearchHit hit : response.getHits().getHits()) {System.out.println(hit.getSourceAsMap());}}3、prefix 查詢
前綴查詢,可以通過一個關鍵字去指定一個field 的前綴,從而查詢到指定文檔
#prefix 查詢 POST /sms-logs-index/sms-logs-type/_search {"query": {"prefix": {"corpName": {"value": "海"}}} } #match 查詢 在這里是什么都查不到的 和上邊的prefix 做比較 POST /sms-logs-index/sms-logs-type/_search {"query": {"match": {"corpName": "海"}} } public void findByPrefix() throws IOException {// 創建request對象SearchRequest request = new SearchRequest(index);request.types(type);// 指定查詢條件SearchSourceBuilder builder = new SearchSourceBuilder();//--------------------------------------------------builder.query(QueryBuilders.prefixQuery("corpName","阿"));//------------------------------------------------------request.source(builder);// 執行SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 輸出結果for (SearchHit hit : response.getHits().getHits()) {System.out.println(hit.getSourceAsMap());}}4、 fuzzy 查詢
模糊查詢,我們可以輸入一個字符的大概,ES 可以根據輸入的大概去匹配內容。查詢結果不穩定
#fuzzy 查詢 POST /sms-logs-index/sms-logs-type/_search {"query": {"fuzzy": {"corpName": {"value": "騰訊客堂",#指定前邊幾個字符是不允許出現錯誤的"prefix_length": 2}}} } public void findByFuzzy() throws IOException {// 創建request對象SearchRequest request = new SearchRequest(index);request.types(type);// 指定查詢條件SearchSourceBuilder builder = new SearchSourceBuilder();//--------------------------------------------------builder.query(QueryBuilders.fuzzyQuery("corpName","騰訊客堂").prefixLength(2));//------------------------------------------------------request.source(builder);// 執行SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 輸出結果for (SearchHit hit : response.getHits().getHits()) {System.out.println(hit.getSourceAsMap());}}5、wildcard 查詢
通配查詢,同mysql中的like 是一樣的,可以在查詢時,在字符串中指定通配符*和占位符?
#wildcard 查詢 POST /sms-logs-index/sms-logs-type/_search {"query": {"wildcard": {"corpName": {"value": "海爾*"}}} }#wildcard 查詢 POST /sms-logs-index/sms-logs-type/_search {"query": {"wildcard": {"corpName": {"value": "海爾??"}}} } public void findByWildCard() throws IOException {// 創建request對象SearchRequest request = new SearchRequest(index);request.types(type);// 指定查詢條件SearchSourceBuilder builder = new SearchSourceBuilder();//--------------------------------------------------builder.query(QueryBuilders.wildcardQuery("corpName","海爾*"));//------------------------------------------------------request.source(builder);// 執行SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 輸出結果for (SearchHit hit : response.getHits().getHits()) {System.out.println(hit.getSourceAsMap());}}6、rang 查詢
范圍查詢,只針對數值類型,對一個field 進行大于或者小于的范圍指定
#rang 查詢 POST /sms-logs-index/sms-logs-type/_search {"query": {"range": {"fee": {"gte": 10,"lte": 20}}} } public void findByRang() throws IOException {// 創建request對象SearchRequest request = new SearchRequest(index);request.types(type);// 指定查詢條件SearchSourceBuilder builder = new SearchSourceBuilder();//--------------------------------------------------builder.query(QueryBuilders.rangeQuery("fee").gt(10).lte(30));//------------------------------------------------------request.source(builder);// 執行SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 輸出結果for (SearchHit hit : response.getHits().getHits()) {System.out.println(hit.getSourceAsMap());}}8、 regexp 查詢
正則查詢,通過你編寫的正則表達式去匹配內容
Ps:prefix wildcard fuzzy 和regexp 查詢效率比較低 ,在要求效率比較高時,避免使用
四、深分頁 scroll
ES 對from +size時又限制的,from +size 之和 不能大于1W,超過后 效率會十分低下
原理:
from+size ES查詢數據的方式,
第一步將用戶指定的關鍵詞進行分詞,
第二部將詞匯去分詞庫中進行檢索,得到多個文檔id,
第三步去各個分片中拉去數據, 耗時相對較長
第四步根據score 將數據進行排序, 耗時相對較長
第五步根據from 和size 的值 將部分數據舍棄,
第六步,返回結果。
scroll +size ES 查詢數據的方式
第一步將用戶指定的關鍵詞進行分詞,
第二部將詞匯去分詞庫中進行檢索,得到多個文檔id,
第三步,將文檔的id放在一個上下文中
第四步,根據指定的size去ES中檢索指定個數數據,拿完數據的文檔id,會從上下文中移除
第五步,如果需要下一頁的數據,直接去ES的上下文中找后續內容。
第六步,循環第四步和第五步
scroll 不適合做實時查詢。
五、delete-by-query
根據term,match 等查詢方式去刪除大量索引
PS:如果你要刪除的內容,時index下的大部分數據,推薦創建一個新的index,然后把保留的文檔內容,添加到全新的索引
六、復合查詢
復合過濾器,將你的多個查詢條件 以一定的邏輯組合在一起,
must:所有條件組合在一起,表示 and 的意思
must_not: 將must_not中的條件,全部都不匹配,表示not的意思
should:所有條件用should 組合在一起,表示or 的意思
boosting 查詢
boosting 查詢可以幫助我們去影響查詢后的score
- positive:只有匹配上positive 查詢的內容,才會被放到返回的結果集中
- negative: 如果匹配上了positive 也匹配上了negative, 就可以 降低這樣的文檔score.
- negative_boost:指定系數,必須小于1 0.5
關于查詢時,分數時如何計算的:
- 搜索的關鍵字再文檔中出現的頻次越高,分數越高
- 指定的文檔內容越短,分數越高。
- 我們再搜索時,指定的關鍵字也會被分詞,這個被分詞的內容,被分詞庫匹配的個數越多,分數就越高。
七、filter 查詢
query 查詢:根據你的查詢條件,去計算文檔的匹配度得到一個分數,并根據分數排序,不會做緩存的。
filter 查詢:根據查詢條件去查詢文檔,不去計算分數,而且filter會對經常被過濾的數據進行緩存。
#filter 查詢 POST /sms-logs-index/sms-logs-type/_search {"query": {"bool": {"filter": [{"term": {"corpName": "海爾智家公司"}},{"range":{"fee":{"lte":50}}}]}} } public void filter() throws IOException {// 1.searchRequestSearchRequest searchRequest = new SearchRequest(index);searchRequest.types(type);// 2.指定查詢條件SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();BoolQueryBuilder boolBuilder = QueryBuilders.boolQuery();boolBuilder.filter(QueryBuilders.termQuery("corpName","海爾智家公司"));boolBuilder.filter(QueryBuilders.rangeQuery("fee").gt(20));sourceBuilder.query(boolBuilder);searchRequest.source(sourceBuilder);// 3.執行SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);// 4. 輸出結果for (SearchHit hit : response.getHits().getHits()) {System.out.println(hit.getSourceAsMap());System.out.println(hit.getId()+"的分數是:"+hit.getScore());}}八、高亮查詢
高亮查詢就是用戶輸入的關鍵字,以一定特殊樣式展示給用戶,讓用戶知道為什么這個結果被檢索出來
高亮展示的數據,本身就是文檔中的一個field,單獨將field以highlight的形式返回給用戶
ES提供了一個highlight 屬性,他和query 同級別。
- frament_size: 指定高亮數據展示多少個字符回來
- pre_tags:指定前綴標簽
- post_tags:指定后綴標簽
九、聚合查詢
ES的聚合查詢和mysql 的聚合查詢類似,ES的聚合查詢相比mysql 要強大得多。ES提供的統計數據的方式多種多樣。
#ES 聚合查詢的RSTFul 語法 POST /index/type/_search {"aggs":{"(名字)agg":{"agg_type":{"屬性":"值"}}} }1、去重計數聚合查詢
去重計數,cardinality 先將返回的文檔中的一個指定的field進行去重,統計一共有多少條
# 去重計數 查詢 province POST /sms-logs-index/sms-logs-type/_search {"aggs": {"provinceAgg": {"cardinality": {"field": "province"}}} } public void aggCardinalityC() throws IOException {// 1.創建requestSearchRequest request = new SearchRequest(index);request.types(type);// 2. 指定使用聚合查詢方式SearchSourceBuilder builder = new SearchSourceBuilder();builder.aggregation(AggregationBuilders.cardinality("provinceAgg").field("province"));request.source(builder);// 3.執行查詢SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.輸出返回結果Cardinality agg = response.getAggregations().get("provinceAgg");System.out.println(agg.getValue());}2、范圍統計
統計一定范圍內出現的文檔個數,比如,針對某一個field 的值再0100,100200,200~300 之間文檔出現的個數分別是多少
范圍統計 可以針對 普通的數值,針對時間類型,針對ip類型都可以響應。
數值 rang
時間 date_rang
ip ip_rang
3、統計聚合
他可以幫你查詢指定field 的最大值,最小值,平均值,平方和…
使用 extended_stats
4、其他聚合查詢 查看官方文檔
https://www.elastic.co/guide/en/elasticsearch/reference/6.8/search-aggregations-metrics-weight-avg-aggregation.html
十、 地圖經緯度搜索
#創建一個經緯度索引,指定一個 name ,一個location PUT /map {"settings": {"number_of_shards": 5,"number_of_replicas": 1},"mappings": {"map":{"properties":{"name":{"type":"text"},"location":{"type":"geo_point"}}}} }#添加測試數據 PUT /map/map/1 {"name":"天安門","location":{"lon": 116.403694,"lat":39.914492} }PUT /map/map/2 {"name":"百望山","location":{"lon": 116.26284,"lat":40.036576} }PUT /map/map/3 {"name":"北京動物園","location":{"lon": 116.347352,"lat":39.947468} }1、ES 的地圖檢索方式
geo_distance :直線距離檢索方式
geo_bounding_box: 以2個點確定一個矩形,獲取再矩形內的數據
geo_polygon:以多個點,確定一個多邊形,獲取多邊形的全部數據
2、基于RESTFul 實現地圖檢索
geo_distance
#geo_distance POST /map/map/_search {"query": {"geo_distance":{#確定一個點"location":{"lon":116.434739,"lat":39.909843},#確定半徑"distance":20000,#指定形狀為圓形"distance_type":"arc"}} } #geo_bounding_box POST /map/map/_search {"query":{"geo_bounding_box":{"location":{"top_left":{"lon":116.327805,"lat":39.95499},"bottom_right":{"lon": 116.363162,"lat":39.938395}}}} } #geo_polygon POST /map/map/_search {"query":{"geo_polygon":{"location":{# 指定多個點確定 位置"points":[{"lon":116.220296,"lat":40.075013},{"lon":116.346777,"lat":40.044751},{"lon":116.236106,"lat":39.981533} ]}}} }3、 java 實現 geo_polygon
public class GeoDemo {RestHighLevelClient client = EsClient.getClient();String index = "map";String type="map";@Testpublic void GeoPolygon() throws IOException {// 1.創建searchRequestSearchRequest request = new SearchRequest(index);request.types(type);// 2.指定 檢索方式SearchSourceBuilder builder = new SearchSourceBuilder();List<GeoPoint> points = new ArrayList<>();points.add(new GeoPoint(40.075013,116.220296));points.add(new GeoPoint(40.044751,116.346777));points.add(new GeoPoint(39.981533,116.236106));builder.query(QueryBuilders.geoPolygonQuery("location",points));request.source(builder);// 3.執行SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.輸出結果for (SearchHit hit : response.getHits().getHits()) {System.out.println(hit.getSourceAsMap());}} }參考:https://github.com/changxuepeng/ElasticsearchStudy/blob/master/ES%E7%AC%94%E8%AE%B0/ES%E7%AC%94%E8%AE%B0.md
總結
以上是生活随笔為你收集整理的Elasticsearch学习4《Elasticsearch的各种查询》的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php 建行外联平台退款
- 下一篇: 踏青-百望山