ElasticSearch偶爾查詢不到數據
1.數據刷新策略
現象:每次insert之后,立刻查詢es的數據是有可能查不到的,因為es從內存寫到磁盤需要時間
原因:es默認每1s執行一次refresh,因此文檔實時性被提高到1s,這也是es被稱為近實時的原因
解決方法:寫的時候指定數據刷新策略, request().setRefreshPolicy(RefreshPolicy.IMMEDIATE);
枚舉org.elasticsearch.action.support.WriteRequest.RefreshPolicy定義了三種策略:
NONE, IMMEDIATE, WAIT_UNTIL;
2.查詢條件中含有中文導致查詢不到數據
elasticsearch 里默認的standard分詞器是會將每一個中文都進行了分詞的切割,
所以你直接想查一整個詞,或者一整句話是無返回結果的。
解決辦法:
1.查詢條件字增加.keyword后綴
QueryBuilders.termQuery("filed.keyword", "查詢中文內容")
2.text類型字段的分詞器 也可以用 "analyzer": "standard_cjk_analyzer" 或者IK分詞器 除了英文外 還支持中日韓 不敏感大小寫
解釋:ElasticSearch 5.0以后,string類型有重大變更,移除了string類型,string字段被拆分成兩種新的數據類型: text用於全文搜索的,而keyword用於關鍵詞搜索
參考文章:https://www.jianshu.com/p/26744eb914a8
不符合條件的數據查詢出來了
當字段值為復雜數據類型(Object、Geo-Point等)的時候,ES內部實際是以扁平化的方式保存數據的:
比如:這兩條數據

PUT /order/_doc/1 { "order_name": "xiaomi order", "desc": "shouji zhong de zhandouji", "goods_count": 3, "total_price": 12699, "goods_list": [ { "name": "xiaomi PRO MAX 5G", "price": 4999 }, { "name": "ganghuamo", "price": 19 }, { "name": "shoujike", "price": 1999 } ] } PUT /order/_doc/2 { "order_name": "Cleaning robot order", "desc": "shouji zhong de zhandouji", "goods_count": 2, "total_price": 12699, "goods_list": [ { "name": "xiaomi cleaning robot order", "price": 1999 }, { "name": "dishwasher", "price": 4999 } ] }
在ES中會這么存儲
{ "order_name": "Cleaning robot order", "desc": "shouji zhong de zhandouji", "goods_count": 2, "total_price": 12699, "goods_list.name":[ "alice", "cleaning", "robot", "order", "dishwasher" ], "goods_list.price":[ 1999, 4999 ] }
當我們執行查詢語句
GET order/_search { "query": { "bool": { "must": [ { "match": { "goods_list.name": "dishwasher" // 條件一 } }, { "match": { "goods_list.price": 1999 // 條件二 } } ] } } }
會把不存在的數據查詢出來(滿足條件之一都會查出來)
上述問題解決辦法即對復雜類型使用Nested類型。參考csdn: https://blog.csdn.net/wlei0618/article/details/126508180
執行查詢時 在query外層嵌套一層查詢: 如下:
GET /order/_search { "query": { "nested": { "path": "goods_list", "query": { "bool": { "must": [ { "match": { "goods_list.name": "dishwasher" } }, { "match": { "goods_list.price": 4999 } } ] } } } } }
注意點:當字段優化改成nested類型的時候 需要把查詢語句一並改動
每次查詢最大只能查10000條
通過資料的查閱,發現默認值是10000,如果要查詢大於10000條,我們就需要修改es的max_result_window默認值
解決方法:
我們在創建索引的時候 設置:"index.max_result_window": "10000", 這個值默認一萬,我們可以改成自己想要的值
Mapping和分片數不能更改
不能改的原因參考以前博客:https://www.cnblogs.com/ssskkk/p/11657465.html#_label4
我如果想更改咋辦 比如數據量太多,分片不夠用,或者Mapping因為業務變化增加字段
1.新建索引,重新映射Mapping
2.Reindex遷移數據
3.然后使用別名,替換用戶的訪問。
批量操作不回滾
說明:批量時不會因為⼀個失敗⽽全部失敗,⽽是繼續執⾏后續操作,在返
回時按照執⾏的狀態返回!
更新⽂檔
更新⽂檔 說明: 這種更新⽅式是先刪除原始⽂檔,在將更新⽂檔以新的內容插⼊。 PUT /products/_doc/sjfYnXwBVVbJgt24PlVU { "title":"iphon15" } 說明: 這種⽅式可以將數據原始內容保存,並在此基礎上更新。 POST /products/_doc/sjfYnXwBVVbJgt24PlVU/_update { "doc" : { "title" : "iphon15" } }
ES性能優化
1. 因為ES不能改變分片數量,所以創建索引的時候要指定好分片數量
ES 默認為一個索引創建 5 個主分片, 並分別為每個分片創建一個副本分片。
解決辦法:合理的分片數量可以提高寫入性能和穩定性。
分片數可以理解為MySQL中的分庫分表
ES查詢主要分為兩類:單ID查詢以及分頁查詢。
分片數越大,集群橫向擴容規模也更大,根據分片路由的單ID查詢吞吐量也能大大提升,但聚合的分頁查詢性能則將降低;
分片數越小,集群橫向擴容規模也更小,單ID的查詢性能也會下降,但分頁查詢的性能將會提升。
2、避免深分頁查詢ES集群的分頁查詢支持from和size參數,
查詢的時候,每個分片必須構造一個長度為from+size的優先隊列,
然后回傳到網關節點,網關節點再對這些優先隊列進行排序找到正確的size個文檔。
假設在一個有6個主分片的索引中,from為10000,size為10,每個分片必須產生10010個結果,
在網關節點中匯聚合並60060個結果,最終找到符合要求的10個文檔。
由此可見,當from足夠大的時候,就算不發生OOM,也會影響到CPU和帶寬等,從而影響到整個集群的性能。
所以應該避免深分頁查詢,盡量不去使用。
解決辦法:可以使用ES的Scroll滾動查詢
scroll 可以先查詢出一些數據,然后再緊接着依次往下查詢。在第一次查詢的時候會有一個滾動id,
相當於一個錨標記 ,隨后再次滾動搜索會需要上一次搜索滾動id,根據這個進行下一次的搜索請求。
每次搜索都是基於一個歷史的數據快照,查詢數據的期間,如果有數據變更,那么和搜索是沒有關系的。
性能會比上面說的分頁性能要高很多,基本上都是毫秒級的。
這個適合於那種類似微博下拉翻頁的,不能隨意跳到任何一頁的場景。
具體官網文檔:https://www.elastic.co/guide/cn/elasticsearch/guide/current/scroll.html
3.導入大量數據時的優化
當數據添加到索引后並不能馬上被查詢到,等到索引刷新后才會被查詢到。 refresh_interval 配置的刷新間隔。
當我們大批量的往Elasticsearch索引錄入數據時,通常會把refresh_interval 設置為 -1,這樣會加快數據導入的速度,在數據導入完成后,再將該參數設置為正數。比如:1s。
當 refresh_interval 為 -1 時,意味着不刷新索引。
refresh_interval 的默認值是 1s。
參考知乎:https://zhuanlan.zhihu.com/p/378295340