天天看點

嚴選 | Elasticsearch中文社群201901錯題本

題記

馬雲演講中曾經提到:很多時候少聽成功專家的話。所有的創業者多花點時間學習别人是怎麼失敗的,因為成功的原因有千千萬萬,失敗的原因就一兩個點。

創業需要關注别人的失敗,而開發實戰,别人的錯誤經驗、别人的問題也非常有價值。

開發最懊悔的事莫過于:自己費盡腦汁、花費了很長時間解決了問題,原來别人在社群或者别的地方早已經給出了更優化的方案。

開發最最懊悔的事莫過于:别人已經給出了方案,但是我們仍然在黑暗中苦逼的摸索。

是以,我從2018年4月——至今,每月都會梳理出了Elasticsearch中文社群的精華幹貨——簡稱:Elastic錯題本,

問題大多來自Medcl、wood大叔等大牛的精彩回複,結合實戰嚴選的核心問題。

放在了GitHub上。

GitHub位址:

https://github.com/laoyang360/deep_elasticsearch/tree/master/es_accumulate

目的:提前加深認知,少重複走别人的彎路!

1、kibana根據曆史資料預測未來資料

Elastic 的機器學習功能剛好就能做

https://www.elastic.co/products/stack/machine-learning

2、es查詢問題。

另外你要注意一下 Lucene 的文法規則:

https://lucene.apache.org/core/2_9_4/queryparsersyntax.html

a+(D|d) 這裡 a 是可選,括号内的必要的。如果要 a 是必要條件,加号要放前面。如果是兩個關鍵字直接是任意滿足的關系,一般是用||。另外注意括号的全角和半角。

如:+a +(c||d)

3、【重要】關于elasticsearch中filter的粒度的疑問

推薦閱讀:

https://elasticsearch.cn/question/6667

filter是單個緩存的,不過對于term 類型的filter是否緩存要看版本。

因為term filter開銷很小,是以從5.1.1之後不再做緩存。

filter上下文中的查詢是獨立被cache的,是以按照你給的例子,應該是三個。

相關的資料在這裡:

https://www.elastic.co/guide/cn/elasticsearch/guide/current/filter-caching.html#_

獨立的過濾器緩存

隻不過從5.1.1版本以後開始,term query不會被cache了。

其他類型的query,比方說range query,各種geo的query依然會被cache起來。 這點隻有在5.1.1的release notes有提及。

4、ES2.3版本,delete一個索引,master日志并沒有記錄相關delete操作?

【原因】

PUT _cluster/settings
{
  "persistent": {
    "logger.cluster.service": "DEBUG"
  }
}           

打開cluster.service的debug,能看到建立、删除索引的日志

低版本位址:

https://www.elastic.co/guide/en/elasticsearch/guide/current/logging.html

高版本位址;

https://www.elastic.co/guide/en/elasticsearch/reference/6.6/logging.html

5、【重要】es gc overhead 報錯

通過scroll方式查詢時,特别注意要設定遊标有效時間不能太久,

例如scroll=30min,過期時間越長對應資料儲存在ES記憶體中就越久,ES記憶體越大。

srcoll查詢完後要及時調用clearScroll(scrollId)來清理對應遊标資料。

https://elasticsearch.cn/question/6578

6、es5.5版本,當文檔字段是1100多個的時候,報異常

Limit of total fields [1000] in index [nfvoemspm] has been exceeded

修改settings

{
"index.mapping.total_fields.limit": 2000
}           

話說真的需要這麼多字段放在一起嗎,能不能從設計上優化一下。

7、Elasticsearch技術棧選型推薦

https://elasticsearch.cn/question/6676
方案1:

SpringBoot+Thymeleaf+RestHighLevelClient

方案2:

SpringBoot

簡單的語句用String.format複雜語句用Freemarker

然後用RestHighLevelClient甚至直接自己包裝一個HttpClient

結合ES自己的template使用

git封裝參考:

https://github.com/godlockin/searchHandler

8、【警惕】資料丢失啦

https://elasticsearch.cn/question/6650

問題:今天發現ES 伺服器上所有機器的所有資料都消失了。 沒有進行過任何操作。

求教有什麼原因可以導緻這種結果.不管是正常的非正常的,能給個指教就是好事。

運維同學抓破頭也沒找到問題出在哪

【根因】:運維人員通過head插件把相關index删除了,而且是憤世嫉俗一般的全部删掉。 現在我更關心如何做安全政策

https://blog.csdn.net/laoyang360/article/details/86347480

你的Elasticsearch在裸奔嗎?

【注意事項】

1.是否暴露了公網通路
2.是否有團隊/公司裡其他人知道位址
3.檢查一下資料導入的腳本有沒有重新開機、oom、做過濾…
4.差不差錢,不差錢的買個xpack做安全政策,差錢就内網隔離部署+黑白名單,亡羊補牢猶未晚矣
5.rerun一下資料導入腳本進行資料修複
6.找到原因了之後不管多妖或者多蠢,都記得回來這裡發個文章,詳細的聊聊整個issue的前因後果
7、先看一下資料路徑裡面的資料是否正常;
8、看一下是否開啟了通配符資料删除;
9、看一下 ES 日志,從中找是否叢集啟停過之類的操作
10、确認下磁盤是不是滿了,導緻的異常或者磁盤路徑的問題           

9、有關es forceMerge問題

https://elasticsearch.cn/question/6563

通過Kibana觀察到 每次強制給某個索引合并段時 都會發現該索引的所占空間會跟随段合并暴漲一倍;

現在問題是這樣的;磁盤空間所剩的空間 不足以撐起某個要合并段的索引的體積的兩倍大小

那麼這個索引是不是就不能合并了 如果仍執行強制合并段 會發生什麼?

回複:es的合并,是将要合并的segment讀取出來,再寫入到新的segment,然後删除老的segment,是以,消耗大量的資源和磁盤空間。
你這樣的情況,建議加大磁盤,或者限制索引合并的線程數量,減小每次合并的segment數量。           

10、beats如何通過配置删除host字段

最近在做日志采集,發現filebeat和winlogbeat采集日志的時候,會有host這個字段,但是是個object字段,es裡日志索引host是text類型,想在agent裡直接通過參數把host字段,可以做到麼?看了下配置,好像沒有找到

你可以通過添加 processors 實作字段過濾的功能,例如

processors:
 - drop_fields:
     when:
        condition
     fields: ["field1", "field2", ...]           

具體請參考:

https://www.elastic.co/guide/en/beats/filebeat/current/defining-processors.html

11、有沒有 ngram 和 wildcard 折中方案?

https://elasticsearch.cn/question/6733

想支援英文的部分搜尋,比如 good,搜尋oo也可以比對出來。這就需要 ngram,但是 ngram 使得 index 占用空間10X+增大,有點無法接受。wildcard 搜尋效率又實在太低。有什麼折中方案麼?

你可以試試字首搜尋

good 你分詞為 good/ood/od/

這樣使用字首搜尋就可以實作你需要的效果;

同時設定一下 mapping,可進一步加快搜尋速度

"index_prefixes": {
    "min_chars": 1,
    "max_chars": 10
  }           

12、 logstash吞吐量太低了怎麼優化呢?

https://elasticsearch.cn/question/6739

Logstash 性能調優主要參數

pipeline.workers:

設定啟動多少個線程執行

fliter 和 output

當 input 的内容出現堆積而 CPU 使用率還比較充足時,可以考慮增加該參數的大小;

`

pipeline.batch.size:

設定單個工作線程在執行過濾器和輸出之前收集的最大事件數,較大的批量大小通常更高效,但會增加記憶體開銷。輸出插件會将每個批處理作為一個輸出單元。;

例如,ES 輸出會為收到的每個批次發出批量請求;調整 pipeline.batch.size 可調整發送到 ES 的批量請求(Bulk)的大小;

pipeline.batch.delay:

設定 Logstash 管道的延遲時間, 管道批處理延遲是 Logstash 在目前管道工作線程中接收事件後等待新消息的最長時間(以毫秒為機關);

簡單來說,當 pipeline.batch.size 不滿足時,會等待 pipeline.batch.delay 設定的時間,逾時後便開始執行 filter 和 output 操作。

請根據具體情況,調整 batch.size 或者 works 的數量

13、請教一個多索引字段比對查詢寫法的問題

想要實作的功能例子如下:

有2個索引: company person

裡面都包含goods和price字段

需要查詢出來company和persion中當goods字段的值一樣時price字段的值不一樣的資料,目前沒有頭緒,請問該怎樣寫呢。

對 goods 字段進行 termsAgg,然後設定其子聚合為對 _index 的 termsAgg 子聚合,并設定 min_doc_count 為 2;

最後設定 _index 的子聚合為 topHits,這樣就可以找到你需要的資料。

{
    "size": 0,
    "query": {
        "match_all": {
            "boost": 1.0
        }
    },
    "aggregations": {
        "goods": {
            "terms": {
                "field": "goods",
                "size": 10000,
                "min_doc_count": 1,
                "shard_min_doc_count": 0,
                "show_term_doc_count_error": false,
                "order": [{
                    "_count": "desc"
                }, {
                    "_key": "asc"
                }],
                "collect_mode": "breadth_first"
            },
            "aggregations": {
                "index": {
                    "terms": {
                        "field": "_index",
                        "size": 10,
                        "min_doc_count": 2,
                        "shard_min_doc_count": 0,
                        "show_term_doc_count_error": false,
                        "order": [{
                            "_count": "desc"
                        }, {
                            "_key": "asc"
                        }]
                    },
                    "aggregations": {
                        "top": {
                            "top_hits": {
                                "from": 0,
                                "size": 100,
                                "version": false,
                                "explain": false
                            }
                        }
                    }
                }
            }
        }
    }
}           

14、search_after的SearchAfterBuilder使用範例:

首先要了解 search_after 這個功能;

例如你現在需要安裝 id 和 time 進行排序;

你擷取了第一頁的結果後,現在需要擷取第二頁内容

你需要使用第一頁最後一條的 id 和 time,作為 search_after 的參數chuan傳遞到查詢請求中。

下面是樣例:

SearchAfterBuilder searchAfterBuilder = new SearchAfterBuilder(); 
searchAfterBuilder.setSortValues(new Object[]{"上一頁的ID", "上一頁的時間"});           

15、ES資料恢複,從red恢複到yellow速度很快,從yellow到green恢複很慢

https://elasticsearch.cn/question/6714

red恢複的時候是從本地加載之前的索引檔案,沒有從别的地方同步,是以比較快。

yellow恢複成GREEN的時候,很大部分都可能是從主shard同步資料,在6.x之前,通常都會很慢。

6.x之後由于translog機制的變更可能會變快,但這裡還要考慮叢集在恢複的時候可能會自己做reblance,同樣涉及到shard跨節點的搬遷

16、ElasticSearch java api,想要實作一次請求查詢多個類型的同時,每個類型隻取固定數量的資料

最近在做系統的搜尋功能,在一個索引下建了一些不同的類型。

頁面上的全局搜尋功能是要求展示所有類型的資料。

一開始想的是按找類型發起請求,每個類型一次,隻取幾條資料。

但是發現查全部類型的時候,雖然單個類型的資料查詢已經解析工作隻需要幾十毫秒,但全部執行完就需要一秒左右了。

是以想要實作隻請求一次,查詢所有類型的資料,并且每個類型隻取固定數量的資料。

請問java api能實作這樣的功能嗎?

【實作】

換一種思路,這麼實作一下,能滿足你的要求。

POST weibo_index/weibo_type,weibo_cm_type/_search
{
  "size": 0,
  "query": {
    "bool": {
      "must": {
        "match": {
          "cont": "北京"
        }
      }
    }
  },
  "aggs": {
    "type_aggs": {
      "terms": {
        "field": "_type",
        "size": 2
      },
      "aggs": {
        "top_hits_aggs": {
          "top_hits": {
            "size": 5,
            "_source": [
              "pt",
              "url"
            ]
          }
        }
      }
    }
  }
}           

17、請問copy_to字段 和 mutil_fields哪種性能好一些呢?

https://elasticsearch.cn/question/6698

因為我們公司業務的原因,我們需要copy_to字段後,然後做全文檢索,那麼我想問一下大家,copy_to字段和直接mutil_field哪種性能更好一些呢?

【參考1】如果隻是簡單的全文搜尋推薦使用 copy_to,性能更佳;

使用 mutil_field 的優點在于每個字段可用設定不同的權重,這樣更有助于優化搜尋結果排名;

此外 copy_to 會比 mutil_field 占用更多一些的存儲

【參考2】

如果是全文檢索,建議使用copy_to,使用更少的字段,性能會更好一些。如果隻是對某個字段單獨去做,就基本上沒有什麼差别。

18、ES重新開機後head插件顯示粉紅色

粉紅色是分片relocating階段正常的顔色變化,稍安勿躁,一會就好了。

粉紅色表示分片在重新配置設定

如果隻是臨時重新開機機器,推薦配置配置設定延遲配置設定政策:

PUT _all/_settings
{
  "settings": {
    "index.unassigned.node_left.delayed_timeout": "5m"
  }
}           

【引申可能原因】:

好像硬碟出問題了吧。把副本調整下,再調整回來,讓他重新配置設定下。1G應該是秒級恢複的。

19、【很有代表性問題】ES比對度的打分問題

使用ES預設的打分規則(TF-IDF),搜尋“葡萄糖”時,搜尋結果中“純淨葡萄糖(食用葡萄糖)”比全比對的“葡萄糖”的得分還要高。因為在前者中“葡萄糖”出現過兩次。

但是我更想要全比對的或比對度更高的,而不關心出現的次數。對我來說,相比“純淨葡萄糖(食用葡萄糖)”,我希望“葡萄糖液”得分更好。

因為“葡萄糖液”中關鍵字占了3/4,即使前者出現兩次“葡萄糖”。

我該怎麼修改?是修改TF-IDF配置,或者修改打分算法,還是自定義打分規則?

【回複】

ES 支援關閉詞頻統計,設定 mapping 即可

PUT /my_index
{
"mappings": {
  "doc": {
    "properties": {
      "text": {
        "type":          "string",
        "index_options": "docs" 
      }
    }
  }
}
}           

将參數 index_options 設定為 docs 可以禁用詞頻統計及詞頻位置,這個映射的字段不會計算詞的出現次數,對于短語或近似查詢也不可用。要求精确查詢的 not_analyzed 字元串字段會預設使用該設定。

https://blog.csdn.net/paditang/article/details/79098830

20、單索引大資料量,如何優化?

【問題】單索引目前已經存儲1.5億多文檔,3節點5分片1副本,每個分片20G多。有定期删除老資料,但是預計在删除老資料前,可能最大存儲文檔達到24億多。

目前想到的解決方案:

1、根據預估的最大24億最大文檔,對目前資源進行擴容。

但是根據之前的資料計算,應該如何合理配置設定分片?如何計算需要擴容幾個節點滿足要求?

2、使用rollover根據條件,索引太大後,寫入資料切換至新索引,但是查詢資料還是對全部索引進行查詢。

這樣可能是多索引,每個索引5分片1副本。

現在疑惑是哪種方案更合理?個人傾向于方案2,比較擴容也是需要成本。

但是方案2後續索引增加,分片增加後,每次查詢是設定查詢别名指向所有索引,這樣查詢性能是不是也會持續下降?

這個推薦先在搜尋壓力小的時段對索引進行一次 ForceMerge,這樣會之前已經删除的文檔進行真正删除操作;

此外,如果搜尋壓力大的化,可以多增加一個副本,這樣副本也可以分擔搜尋的壓力;

如果希望多個索引分擔壓力,可以使用别名,别名可以指定多個索引的某一個索引是可以寫入資料的;

搜尋的時候是全部索引一起搜尋.

【銘毅回複】:

針對方案2:結合template+rollover+别名+curator可以解決問題,不存在性能問題。

相反,針對最新資料的索引,反而通過制定日期索引,會縮減檢索樣本空間,反而效率更高。

【進一步推進閱讀】

6.6 版本索引生命管理

https://elasticsearch.cn/article/6358

21、推薦閱讀新文章

自研基于StanfordNLP的ES分詞插件

https://elasticsearch.cn/article/6341

嚴選 | Elasticsearch中文社群201901錯題本

銘毅天下——Elasticsearch基礎、進階、實戰第一公衆号