Elastic Stack-Elasticsearch使用介紹(五)
一、前言
前4篇將Elasticsearch用法的API和原理方面東西介紹了一下,相信大家對Elasticsearch有了一定的認知,接下我們主要從索引的建立到後期的一些優化做一些介紹;
二、Mapping構建
之前介紹過Index就如同我們的數據庫database,type相當於我們的表,而Mapping就是構建這些字段和索引關系的橋梁。數據庫構建的時候我們要遵守三範式,那Mapping構建的時候我們要考慮那些因素?我認為要有以下幾方面的考慮:
1.字段是什麽類型;
對字段的類型做過介紹,考慮這個時候和數據庫字段設置考慮問題基本一樣;
2.是否需要被檢索,也就是是否需要分詞;
不需要檢索的字段:index設置為false;不需要檢索的字符類型直接設置成keyword類型;
需要檢索的字段,可以通過index_options設定需要的存儲分詞的粒度,主要有以下四種參數docs 、 freqs 、 position 、 offsets,根據需要自行設定;
3.是否需要排序和聚合;
不需要排序或者聚合分析功能:doc_values設置為 false,fielddata設置為 false;
如果一個字段不需要檢索、排序、聚合分析,則enabled設置為false;
4.是否需要另外的存儲;
通過store 設定 true,即可存儲該字段的原始內容,這裏這個舉個例子
以上就是我們建立Mapping時候需要考慮一些東西,接下來我們還有另外一個問題,數據庫中表與表之間是有關聯關系的,這個在Elasticsearch中是如何體現的?
在Elasticsearch中有兩種方式可以去實現關聯關系,
1.Nested Object(嵌套對象)
舉個例子:
這個時候user字段會被映射成為object類型,這個時候JSON文檔會被處理成為:
當我們查詢的時候,就會意外出現的結果;
結果:
Elasticsearch針對這種情況提供Nested Object(嵌套對象)這個解決方案,
增加這一個步驟然後再按照上面步驟操作,就得到我們想要的結果;
當使用Nested Object內部是使用嵌套文檔,當搜索first name為Alice和last name為White的時候就查詢不到;
2.join
join數據類型是在同一個索引通過Parent和Child去指定父文檔和子文檔,然後形成1對多或者1對1的關系,舉個例子:
我這個是5.0以上的版本,不是6.0的版本,這個我還是忘記說,大家註意下版本問題,我大概說下這個意思就是只指定my_join_field字段question的父級為answer;
接下來我們再加入2條父級文檔:
接下來在加入2條子文檔:
這裏需要註意的問題是路由必須要指定,父級文檔必須和自己文檔在同一個分片上,另外就是指定join的文檔和父id;
這個時候我們查看下我們形成的文檔:
{ "took": 13, "timed_out": false, "_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 }, "hits": { "total": 4, "max_score": null, "hits": [ { "_index": "my_index", "_type": "doc", "_id": "1", "_score": null, "_source": { "text": "This is a question", "my_join_field": { "name": "question" } }, "sort": [ "1" ] }, { "_index": "my_index", "_type": "doc", "_id": "2", "_score": null, "_source": { "text": "This is a another question", "my_join_field": { "name": "question" } }, "sort": [ "2" ] }, { "_index": "my_index", "_type": "doc", "_id": "3", "_score": null, "_routing": "1", "_source": { "text": "This is an answer", "my_join_field": { "name": "answer", "parent": "1" } }, "sort": [ "3" ] }, { "_index": "my_index", "_type": "doc", "_id": "4", "_score": null, "_routing": "1", "_source": { "text": "This is another answer", "my_join_field": { "name": "answer", "parent": "1" } }, "sort": [ "4" ] } ] } }View Code
看到結果我們就可以知道我們的1對多關系已經建立起來了,接下來我們按照父id來查詢父id為1的文檔:
這個地方還要提醒下,也是可以使用get的,只是使用神器的時候這樣比較方便;
結果如下:
還可以使用has_child 返回包含某子文檔的父文檔,has_parent 返回包含某父文檔的子文檔這些就不寫例子自己探索一下吧;
接下來做個對比:
註意:Mapping字段不要設置太多;
三、部分優化的意見
elasticsearch.yml中建議設定的參數:
之前集群搭建的時候大家肯定設置一些參數,另外上面你的介紹也設置了一些參數,我們也具體來說下在上生產環境之前到底要設置那些參數:
1.cluster.name集群名稱;
2.node.name節點名稱;
3.node.master是否是主節點;
4.node.data是否存放數據,主節點不建議存放數據;
5.discovery.zen.ping.unicast.hosts設置集群的其他節點;
6.network.host IP;
7.path.data and path.logs 存放記錄和日誌的目錄,默認是在Elasticsearch目錄下;
8.discovery.zen.minimum_master_nodes 集群掛掉以後選舉主的個數;
JVM設置:
1.將最小堆大小(Xms)和最大堆大小(Xmx)設置為彼此相等,防止垃圾回收過於頻繁;
2.將Xmx設置為不超過物理RAM的50%,以確保有足夠的物理RAM用於內核文件系統緩存;
3.不要超過32GB,這是JVM優化的建議;
分片的設置:
建議閱讀這篇文章;
讀寫優化:
寫入的優化,這個參考下Elastic Stack-Elasticsearch使用介紹(三)這篇文章,這篇文章我介紹寫入時候的一些步驟,我們優化的方向就是從這3個方向:
當然要貫徹多線程、批量寫入這個不能變得方針,針對refresh、translog、flush這3個方面做優化:
1.refresh
每refresh一次都會生成一個segment,如果refresh頻率過高,可能會照成segment包含的文檔數是很少,生成很多的segment;
調整方向
增大refresh_interval,降低實時性,默認是1s,設置為-1直接禁止自動refresh;
增大緩存區的大小,參數為indices.memory.index_buffer_size(靜態參數,在elasticsearch.yml中設定,該參數設置後必須重啟節點),默認為10%;
2.translog
目標是降低translog寫磁盤的頻率,從而提高效率,但是這樣就會有掉丟數據的風險;
調整方向
index.translog.durabiliy設置為asyn,index.translog.sync_interval設置寫入時間的間隔,單位是秒,比如10s,那麽translog會改為每10s寫一次磁盤,這個時候如果宕機就會丟失數據;
index.translog.flush_threshold_size 默認為512MB,超過該大小時會觸發一次flush;
3.合理設置節點和分片的個數,通過設置index.routing.allocation.total_shards_per_node 限定每個索引在每個節點上可分配的總主副分片的個數;
讀取的優化:
1.合理設置分片數
通過測試一個分片性能,然後根據業務進行計算,設置合理的分片個數;怎麽測試一個分片的性能?首先搭建與生產一樣的環境,接下來設定一個單分片無副本的索引,然後進行寫入數據測試 和查詢數據,然後根據提供的監控指標進行監控壓力測試的情況,這部分監控內容下一章進行講解;壓測工具可以使用esrally,參考下這篇文章;
2.優化查詢語句
盡量使用Filter上下文,減少算分的場景,由於Filter有緩存機制,可以提升查詢性能;
四、結束
接下來會開始說一說監控的問題,歡迎大家加群438836709,歡迎大家關註我公眾號!
Elastic Stack-Elasticsearch使用介紹(五)