1. 程式人生 > >Elastic Stack-Elasticsearch使用介紹(五)

Elastic Stack-Elasticsearch使用介紹(五)

inf _id sync 數據類型 ase 範式 進行 none 存儲

一、前言

前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使用介紹(五)