ElasticSearch搜索引擎:常用的存储mapping配置项 与 doc_values详细介绍
一、ES的數(shù)據(jù)存儲(chǔ)結(jié)構(gòu):
ES底層使用 Lucene 存儲(chǔ)數(shù)據(jù),Lucene 的索引包含以下部分:
A Lucene index is made of several components: an inverted index, a bkd tree, a column store (doc values), a document store (stored fields) and term vectors, and these components can communicate thanks to these doc ids.
?其中:
- inverted index:倒排索引。
- bkd tree: Block k-d tree,用于在高維空間內(nèi)做索引,如地理坐標(biāo)的索引。
- column store:doc values,列式存儲(chǔ),批量讀取連續(xù)的數(shù)據(jù)以提高排序和聚合的效率。
- document store:Store Fileds,行式存儲(chǔ)文檔,用于控制 doc 原始數(shù)據(jù)的存儲(chǔ),其中占比最大的是 source 字段。
- term vectors:用于存儲(chǔ)各個(gè)詞在文檔中出現(xiàn)的位置等信息。
?
二、ES常見(jiàn)配置項(xiàng)說(shuō)明:
在很多場(chǎng)合下,我們并不需要存儲(chǔ)上述全部信息,因此可以通過(guò)設(shè)置 mappings 里面的屬性來(lái)控制哪些字段是我們需要存儲(chǔ)的、哪些是不需要存儲(chǔ)的。而 ES 的 mapping 中有很多設(shè)置選項(xiàng),這些選項(xiàng)如果設(shè)置不當(dāng),有的可能浪費(fèi)存儲(chǔ)空間,有的可能導(dǎo)致無(wú)法使用 Aggregation,有的可能導(dǎo)致不能檢索。下面就簡(jiǎn)單介紹下 ES 中常見(jiàn)的存儲(chǔ)與檢索的 mapping 配置項(xiàng):
| 配置項(xiàng) | 作用 | 注意事項(xiàng) | 默認(rèn)值 |
| _all | 提供跨字段全文檢索 | (1)會(huì)占用額外空間,把 mapping 中的所有字段通過(guò)空格拼接起來(lái)做索引,在跨字段全文檢索才需要打開(kāi); (2)在 v6.0+已被棄用,v7.0會(huì)正式移除,可以使用 [copy_to] 來(lái)自定義組合字段 | 關(guān)閉 |
| _source | 存儲(chǔ) post 提交到ES的原始 json 內(nèi)容 | (1)會(huì)占用很多存儲(chǔ)空間。數(shù)據(jù)壓縮存儲(chǔ),讀取會(huì)有額外解壓開(kāi)銷(xiāo)。 (2)不需要讀取原始字段內(nèi)容可以考慮關(guān)閉,但關(guān)閉后無(wú)法 reindex | 開(kāi)啟 |
| store | 是否單獨(dú)存儲(chǔ)該字段 | (1)會(huì)占用額外存儲(chǔ)空間,與 source 獨(dú)立,同時(shí)開(kāi)啟 store 和 source 則會(huì)將該字段原始內(nèi)容保存兩份,不同字段單獨(dú)存儲(chǔ),不同字段的數(shù)據(jù)在磁盤(pán)上不連續(xù),若讀取多個(gè)字段則需要查詢多次,如需讀取多個(gè)字段,需權(quán)衡比較 source 與 store 效率 | 關(guān)閉 |
| doc_values | 支持排序、聚合 | 會(huì)占用額外存儲(chǔ)空間,與 source 獨(dú)立,同時(shí)開(kāi)啟 doc_values 和 _source 則會(huì)將該字段原始內(nèi)容保存兩份。doc_values 數(shù)據(jù)在磁盤(pán)上采用列式存儲(chǔ),關(guān)閉后無(wú)法使用排序和聚合 | 開(kāi)啟 |
| index | 是否加入倒排索引 | 關(guān)閉后無(wú)法對(duì)其進(jìn)行搜索,但字段仍會(huì)存儲(chǔ)到 _source 和 doc_values,字段可以被排序和聚合 | 開(kāi)啟 |
| enabled | 是否對(duì)該字段進(jìn)行處理 | 關(guān)閉后,只在 _source中存儲(chǔ),類(lèi)似 index 與 doc_values 的總開(kāi)關(guān) | 開(kāi)啟 |
在ES的 mapping 設(shè)置里,all,source 是 mapping 的元數(shù)據(jù)字段(Meta-Fields),store、doc_values、enabled、index 是 mapping 參數(shù)。
1、_all:
all 字段的作用是提供跨字段查詢的支持,把 mapping 中的所有字段通過(guò)空格拼接起來(lái)做索引。ES在查詢的過(guò)程中,需要指定在哪一個(gè)field里面查詢。
{“name”: “smith”,“email”: "John@example.com" }用戶在查詢時(shí),想查詢叫做 John 的人,但不知道 John 出現(xiàn)在 name 字段中還是在 email 字段中,由于ES是為每一個(gè)字段單獨(dú)建立索引,所以用戶需要以 John 為關(guān)鍵詞發(fā)起兩次查詢,分別查詢name字段和email字段。
如果開(kāi)啟了 all 字段,則ES會(huì)在索引過(guò)程中創(chuàng)建一個(gè)虛擬的字段 all,其值為文檔中各個(gè)字段拼接起來(lái)所組成的一個(gè)很長(zhǎng)的字符串(例如上面的例子,all 字段的內(nèi)容為字符串 “smith John@example.com”)。隨后,該字段將被分詞打散,與其他字段一樣被收入倒排索引中。由于 all 字段包含了所有字段的信息,因此可以實(shí)現(xiàn)跨字段的查詢,用戶不用關(guān)心要查詢的關(guān)鍵詞在哪個(gè)字段中。
由于該字段的內(nèi)容都來(lái)自 source 字段,因此默認(rèn)情況下,該字段的內(nèi)容并不會(huì)被保存,可以通過(guò)設(shè)置 store 屬性來(lái)強(qiáng)制保存 all 字段。開(kāi)啟 all 字段,會(huì)帶來(lái)額外的CPU開(kāi)銷(xiāo)和存儲(chǔ),如果沒(méi)有使用到,可以關(guān)閉 all 字段。
2、_source:
source 字段用于存儲(chǔ) post 到 ES?的原始 json 文檔。為什么要存儲(chǔ)原始文檔呢?因?yàn)?ES 采用倒排索引對(duì)文本進(jìn)行搜索,而倒排索引無(wú)法存儲(chǔ)原始輸入文本。一段文本交給ES后,首先會(huì)被分析器(analyzer)打散成單詞,為了保證搜索的準(zhǔn)確性,在打散的過(guò)程中,會(huì)去除文本中的標(biāo)點(diǎn)符號(hào),統(tǒng)一文本的大小寫(xiě),甚至對(duì)于英文等主流語(yǔ)言,會(huì)把發(fā)生形式變化的單詞恢復(fù)成原型或詞根,然后再根據(jù)統(tǒng)一規(guī)整之后的單詞建立倒排索引,經(jīng)過(guò)如此一番處理,原文已經(jīng)面目全非。因此需要有一個(gè)地方來(lái)存儲(chǔ)原始的信息,以便在搜到這個(gè)文檔時(shí)能夠把原文返回給查詢者。
那么一定要存儲(chǔ)原始文檔嗎?不一定!如果沒(méi)有取出整個(gè)原始 json 結(jié)構(gòu)體的需求,可以在 mapping 中關(guān)閉 source 字段或者只在 source 中存儲(chǔ)部分字段(使用store)。 但是這樣做有些負(fù)面影響:
- (1)不能獲取到原文
- (2)無(wú)法reindex:如果存儲(chǔ)了 source,當(dāng) index 發(fā)生損壞,或需要改變 mapping 結(jié)構(gòu)時(shí),由于存在原始數(shù)據(jù),ES可以通過(guò)原始數(shù)據(jù)自動(dòng)重建index,如果不存 source 則無(wú)法實(shí)現(xiàn)
- (3)無(wú)法在查詢中使用script:因?yàn)?script 需要訪問(wèn) source 中的字段
3、store:
store 決定一個(gè)字段是否要被單獨(dú)存儲(chǔ)。大家可能會(huì)有疑問(wèn),source 里面不是已經(jīng)存儲(chǔ)了原始的文檔嘛,為什么還需要一個(gè)額外的 store 屬性呢?原因如下:
(1)如果禁用了 source 保存,可以通過(guò)指定 store 屬性來(lái)單獨(dú)保存某個(gè)或某幾個(gè)字段,而不是將整個(gè)輸入文檔保存到 source 中。
(2)如果 source 中有長(zhǎng)度很長(zhǎng)的文本(如一篇文章)和較短的文本(如文章標(biāo)題),當(dāng)只需要取出標(biāo)題時(shí),如果使用 source 字段,ES需要讀取整個(gè) source 字段,然后返回其中的 title,由此會(huì)引來(lái)額外的IO開(kāi)銷(xiāo),降低效率。此時(shí)可以選擇將 title 的 store 設(shè)置為true,在 source 字段外單獨(dú)存儲(chǔ)一份。讀取時(shí)不必在讀取整 source 字段了。但是需要注意,應(yīng)該避免使用 store 查詢多個(gè)字段,因?yàn)?store 的存儲(chǔ)在磁盤(pán)上不連續(xù),ES在讀取不同的 store 字段時(shí),每個(gè)字段的讀取均需要在磁盤(pán)上進(jìn)行查詢操作,而使用 source 字段可以一次性連續(xù)讀取多個(gè)字段。
4、doc_values:
倒排索引可以提供全文檢索能力,但是無(wú)法提供對(duì)排序和數(shù)據(jù)聚合的支持。doc_values 本質(zhì)上是一個(gè)序列化的列式存儲(chǔ)結(jié)構(gòu),適用于聚合(aggregations)、排序(Sorting)、腳本(scripts access to field)等操作。默認(rèn)情況下,ES幾乎會(huì)為所有類(lèi)型的字段存儲(chǔ)doc_value,但是 text 或 text_annotated 等可分詞字段不支持 doc values 。如果不需要對(duì)某個(gè)字段進(jìn)行排序或者聚合,則可以關(guān)閉該字段的doc_value存儲(chǔ)。
5、index:
控制倒排索引,用于標(biāo)識(shí)指定字段是否需要被索引。默認(rèn)情況下是開(kāi)啟的,如果關(guān)閉了 index,則該字段的內(nèi)容不會(huì)被 analyze 分詞,也不會(huì)存入倒排索引,即意味著該字段無(wú)法被搜索。
6、enabled:
這是一個(gè) index 和 doc_value 的總開(kāi)關(guān),如果 enabled 設(shè)置為false,則這個(gè)字段將會(huì)僅存在于 source 中,其對(duì)應(yīng)的 index 和 doc_value 都不會(huì)被創(chuàng)建。這意味著,該字段將不可以被搜索、排序或者聚合,但可以通過(guò) source 獲取其原始值。
7、term_vector:
在對(duì)文本進(jìn)行 analyze 的過(guò)程中,可以保留有關(guān)分詞結(jié)果的相關(guān)信息,包括單詞列表、單詞之間的先后順序、單詞在原文中的位置等信息。查詢結(jié)果返回的高亮信息就可以利用其中的數(shù)據(jù)來(lái)返回。默認(rèn)情況下,term_vector是關(guān)閉的,如有需要(如加速highlight結(jié)果)可以開(kāi)啟該字段的存儲(chǔ)。
?
三、doc_values 詳細(xì)說(shuō)明:
1、doc_values 的作用:
基于 lucene 的 solr 和 es 都是使用倒排索引實(shí)現(xiàn)快速檢索的,也就是通過(guò)建立 "搜索關(guān)鍵詞 ==>文檔ID列表" 的關(guān)系映射實(shí)現(xiàn)快速檢索,但是倒排索引也是有缺陷的,比如我們需要字段值做一些排序、分組、聚合操作,lucene 內(nèi)部會(huì)遍歷提取所有出現(xiàn)在文檔集合的排序字段,然后再次構(gòu)建一個(gè)最終的排好序的文檔集合list,這個(gè)步驟的過(guò)程全部維持在內(nèi)存中操作,而且如果排序數(shù)據(jù)量巨大的話,非常容易就造成solr內(nèi)存溢出和性能緩慢。
doc values 就是在構(gòu)建倒排索引時(shí),會(huì)對(duì)開(kāi)啟 doc values 的字段額外構(gòu)建一個(gè)有序的 "document文檔 ==> field value“ 的列式存儲(chǔ)映射,從而實(shí)現(xiàn)對(duì)指定字段進(jìn)行排序和聚合時(shí)對(duì)內(nèi)存的依賴,提升該過(guò)程的性能。默認(rèn)情況下每個(gè)字段的 doc values 都是開(kāi)啟的,當(dāng)然 doc values 也會(huì)耗費(fèi)一定的磁盤(pán)空間。
另外 doc values 保存在操作系統(tǒng)的磁盤(pán)中,當(dāng) doc values 大于節(jié)點(diǎn)的可用內(nèi)存,ES 可以從操作系統(tǒng)頁(yè)緩存中加載或彈出,從而避免發(fā)生 JVM 內(nèi)存溢出的異常,docValues 遠(yuǎn)小于節(jié)點(diǎn)的可用內(nèi)存,操作系統(tǒng)自然將所有Doc Values存于內(nèi)存中(堆外內(nèi)存),有助于快速訪問(wèn)。
2、doc_values 與 source 的區(qū)別?使用 docvalue_fields 檢索指定的字段?
post 提交到 ES 的原始 Json 文檔都存儲(chǔ)在 source 字段中,默認(rèn)情況下,每次搜索的命中結(jié)果都包含文檔 source,即使僅請(qǐng)求少量字段,也必須加載并解析整個(gè) source 對(duì)象,而 source 每次使用時(shí)都必須加載和解析,所以使用 source 非常慢。為避免該問(wèn)題,當(dāng)我們只需要返回相當(dāng)少的支持 doc_values 的字段時(shí),可以使用 docvalue_fields 參數(shù)獲取選定字段的值。
doc values 存儲(chǔ)與 _source 相同的值,但在磁盤(pán)上基于列的結(jié)構(gòu)中進(jìn)行了優(yōu)化,以進(jìn)行排序和匯總。由于每個(gè)字段都是單獨(dú)存儲(chǔ)的,因此 Elasticsearch 僅讀取請(qǐng)求的字段值,并且可以避免加載整個(gè)文檔 _source。通過(guò) docvalue_fields 可以從建好的列式存儲(chǔ)結(jié)果中直接返回字段值,畢竟 source 是從一大片物理磁盤(pán)去,理論上從 doc values 處拿這個(gè)字段值會(huì)比 source 要快一點(diǎn),頁(yè)面抖動(dòng)少一點(diǎn)。
3、如何在 ES 中使用 doc values?
doc values 通過(guò)犧牲一定的磁盤(pán)空間帶來(lái)的好處主要有兩個(gè):
- 節(jié)省內(nèi)存
- 提升排序,分組等聚合操作的性能
那么我們?nèi)绾问褂?doc values 呢?
(1)我們首先關(guān)注如何激活 doc values,只要開(kāi)啟 doc values 后,排序,分組,聚合的時(shí)候會(huì)自動(dòng)使用 doc values 提速。在 ElasticSearch 中,doc values 默認(rèn)是開(kāi)啟的,比較簡(jiǎn)單暴力,我們也可以酌情關(guān)閉一些不需要使用 doc values 的字段,以節(jié)省磁盤(pán)空間,只需要設(shè)置 doc_values 為 false 就可以了,如下:
"session_id":{"type":"string","index":"not_analyzed","doc_values":false}(2)使用 docvalue_fields 的檢索指定的字段:
GET my-index-000001/_search {"query": {"match": {"user.id": "kimchy"}},"docvalue_fields": ["user.id","http.response.*", {"field": "date","format": "epoch_millis" }] }?
ES搜索指定字段的不同方式,詳情請(qǐng)見(jiàn)官網(wǎng):https://www.elastic.co/guide/en/elasticsearch/reference/7.x/search-fields.html#search-fields
與50位技術(shù)專(zhuān)家面對(duì)面20年技術(shù)見(jiàn)證,附贈(zèng)技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的ElasticSearch搜索引擎:常用的存储mapping配置项 与 doc_values详细介绍的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: ElasticSearch搜索引擎常见面
- 下一篇: Elasticsearch搜索引擎:ES