ES查詢踩兩個坑


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
    }
  ]
}
View Code

在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", 這個值默認一萬,我們可以改成自己想要的值

也可以使用ES的Scroll滾動查詢

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的查詢性能也會下降,但分頁查詢的性能將會提升。

  ES的查詢原理

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM