<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Elasticsearch 運行時類型 Runtime fields 深入詳解

          共 1484字,需瀏覽 3分鐘

           ·

          2021-10-02 17:42

          1、實戰(zhàn)問題

          實戰(zhàn)業(yè)務(wù)中,遇到數(shù)據(jù)導(dǎo)入后,但發(fā)現(xiàn)缺少部分必要字段,一般怎么解決?

          比如:emotion 代表情感值,取值范圍為:0-1000。

          其中:300-700 代表中性;0-300 代表負(fù)面;700-1000 代表正面。

          但實際業(yè)務(wù)中,我們需要:中性:0;負(fù)面:-1;正面:1。

          如何實現(xiàn)呢?

          這時,可能想到的解決方案:

          • 方案一:重新創(chuàng)建索引時添加字段,清除已有數(shù)據(jù)再重新導(dǎo)入數(shù)據(jù)。
          • 方案二:重新創(chuàng)建索引時添加字段,原索引通過 reindex 寫入到新索引。
          • 方案三:提前指定數(shù)據(jù)預(yù)處理,結(jié)合管道 ingest 重新導(dǎo)入或批量更新 update_by_query 實現(xiàn)。
          • 方案四:保留原索引不動,通過script 腳本實現(xiàn)。

          方案一、二類似,新加字段導(dǎo)入數(shù)據(jù)即可。

          方案三、方案四 我們模擬實現(xiàn)一把。

          2、方案三、四實現(xiàn)一把

          2.1 方案三 Ingest 預(yù)處理實現(xiàn)

          DELETE?news_00001
          PUT?news_00001
          {
          ??"mappings":?{
          ????"properties":?{
          ??????"emotion":?{
          ????????"type":?"integer"
          ??????}
          ????}
          ??}
          }

          POST?news_00001/_bulk
          {"index":{"_id":1}}
          {"emotion":558}
          {"index":{"_id":2}}
          {"emotion":125}
          {"index":{"_id":3}}
          {"emotion":900}
          {"index":{"_id":4}}
          {"emotion":600}

          PUT?_ingest/pipeline/my-pipeline
          {
          ??"processors":?[
          ????{
          ??????"script":?{
          ????????"description":?"Set?emotion?flag?param",
          ????????"lang":?"painless",
          ????????"source":?"""
          ??????????if?(ctx['emotion']??0)
          ????????????ctx['emotion_flag']?=?-1;
          ??????????if?(ctx['emotion']?>=?300?&&?ctx['emotion']?<=?700)
          ????????????ctx['emotion_flag']?=?0;
          ??????????if?(ctx['emotion']?>?700?&&?ctx['emotion']?????????????ctx['emotion_flag']?=?1;
          ??????????"""

          ??????}
          ????}
          ??]
          }
          POST?news_00001/_update_by_query?pipeline=my-pipeline
          {
          ??"query":?{
          ????"match_all":?{}
          ??}
          }

          方案三的核心:定義了預(yù)處理管道:my-pipeline,管道里做了邏輯判定,對于emotion 不同的取值區(qū)間,設(shè)置 emotion_flag 不同的結(jié)果值。

          該方案必須提前創(chuàng)建管道,可以通過寫入時指定缺省管道 default_pipeline 或者結(jié)合批量更新實現(xiàn)。

          實際是兩種細(xì)分實現(xiàn)方式:

          • 方式一:udpate_by_query 批量更新。而更新索引尤其全量更新索引是有很大的成本開銷的。
          • 方式二:寫入階段指定預(yù)處理管道,每寫入一條數(shù)據(jù)預(yù)處理一次。

          2.2 方案四 script 腳本實現(xiàn)

          POST?news_00001/_search
          {
          ??"query":?{
          ????"match_all":?{}
          ??},
          ??"script_fields":?{
          ????"emotion_flag":?{
          ??????"script":?{
          ????????"lang":?"painless",
          ????????"source":?"if?(doc['emotion'].value?0)?return?-1;?if?(doc['emotion'].value?>=?300?&&?doc['emotion'].value<=700)?return?0;?if?(doc['emotion'].value?>?700?&&?doc['emotion'].value<=1000)?return?1;"
          ??????}
          ????}
          ??}
          }

          方案四的核心:通過 script_field 腳本實現(xiàn)。

          該方案僅是通過檢索獲取了結(jié)果值,該值不能用于別的用途,比如:聚合。

          還要注意的是:script_field 腳本處理字段會有性能問題。

          兩種方案各有利弊,這時候我們會進(jìn)一步思考:

          能不能不改 Mapping、不重新導(dǎo)入數(shù)據(jù),就能得到我們想要的數(shù)據(jù)呢?

          早期版本不可以,7.11 版本之后的版本有了新的解決方案——Runtime fields 運行時字段。

          3、Runtime fields 產(chǎn)生背景

          Runtime fields 運行時字段是舊的腳本字段 script field 的 Plus 版本,引入了一個有趣的概念,稱為“讀取建?!保⊿chema on read)。

          有 Schema on read 自然會想到 Schema on write(寫時建模),傳統(tǒng)的非 runtime field 類型 都是寫時建模的,而 Schema on read 則是另辟蹊徑、讀時建模。

          這樣,運行時字段不僅可以在索引前定義映射,還可以在查詢時動態(tài)定義映射,并且?guī)缀蹙哂谐R?guī)字段的所有優(yōu)點。

          Runtime fields在索引映射或查詢中一旦定義,就可以立即用于搜索請求、聚合、篩選和排序。

          4、Runtime fields 解決文章開頭問題

          4.1 Runtime fields 實戰(zhàn)求解

          PUT?news_00001/_mapping
          {
          ??"runtime":?{
          ????"emotion_flag_new":?{
          ??????"type":?"keyword",
          ??????"script":?{
          ????????"source":?"if?(doc['emotion'].value?>?0?&&?doc['emotion'].value?=?300?&&?doc['emotion'].value<=700)?emit('0');?if?(doc['emotion'].value?>?700?&&?doc['emotion'].value<=1000)?emit('1');"
          ??????}
          ????}
          ??}
          }

          GET?news_00001/_search
          {
          ??"fields"?:?["*"]
          }

          4.2 Runtime fields 核心語法解讀

          第一:PUT news_00001/_mapping 是在已有 Mapping 的基礎(chǔ)上 更新 Mapping。

          這是更新 Mapping 的方式。實際上,創(chuàng)建索引的同時,指定 runtime field 原理一致。實現(xiàn)如下:

          PUT?news_00002
          {
          ??"mappings":?{
          ????"runtime":?{
          ??????"emotion_flag_new":?{
          ????????"type":?"keyword",
          ????????"script":?{
          ??????????"source":?"if?(doc['emotion'].value?>?0?&&?doc['emotion'].value?=?300?&&?doc['emotion'].value<=700)?emit('0');?if?(doc['emotion'].value?>?700?&&?doc['emotion'].value<=1000)?emit('1');"
          ????????}
          ??????}
          ????},
          ????"properties":?{
          ??????"emotion":?{
          ????????"type":?"integer"
          ??????}
          ????}
          ??}
          }

          第二:更新的什么呢?

          加了字段,確切的說,加了:runtime 類型的字段,字段名稱為:emotion_flag_new,字段類型為:keyword,字段數(shù)值是用腳本 script 實現(xiàn)的。

          腳本實現(xiàn)的什么呢?

          • 當(dāng) emotion 介于 0 到 300 之間時,emotion_flag_new 設(shè)置為 -1 。
          • 當(dāng) emotion 介于 300 到 700 之間時,emotion_flag_new 設(shè)置為 0。
          • 當(dāng) emotion 介于 700 到 1000 之間時,emotion_flag_new 設(shè)置為 1。

          第三:如何實現(xiàn)檢索呢?

          我們嘗試一下傳統(tǒng)的檢索,看一下結(jié)果。

          我們先看一下 Mapping:

          {
          ??"news_00001"?:?{
          ????"mappings"?:?{
          ??????"runtime"?:?{
          ????????"emotion_flag_new"?:?{
          ??????????"type"?:?"keyword",
          ??????????"script"?:?{
          ????????????"source"?:?"if?(doc['emotion'].value?>?0?&&?doc['emotion'].value?=?300?&&?doc['emotion'].value<=700)?emit('0');?if?(doc['emotion'].value?>?700?&&?doc['emotion'].value<=1000)?emit('1');",
          ????????????"lang"?:?"painless"
          ??????????}
          ????????}
          ??????},
          ??????"properties"?:?{
          ????????"emotion"?:?{
          ??????????"type"?:?"integer"
          ????????}
          ??????}
          ????}
          ??}
          }

          多了一個 runtime 類型的字段:emotion_flag_new。

          執(zhí)行:

          GET?news_00001/_search

          返回結(jié)果如下:

          執(zhí)行:

          GET?news_00001/_search
          {
          ??"query":?{
          ????"match":?{
          ??????"emotion_flag_new":?"-1"
          ????}
          ??}
          }

          返回結(jié)果如下:

          執(zhí)行:

          GET?news_00001/_search
          {
          ??"fields"?:?["*"],
          ??"query":?{
          ????"match":?{
          ??????"emotion_flag_new":?"-1"
          ????}
          ??}
          }

          返回結(jié)果如下:

          4.3 Runtime fields 核心語法解讀

          為什么加了:field:[*] 才可以返回檢索匹配結(jié)果呢?

          因為:Runtime fields 不會顯示在:_source 中,但是:fields API 會對所有 fields 起作用。

          如果需要指定字段,就寫上對應(yīng)字段名稱;否則,寫 * 代表全部字段。

          4.4 如果不想另起爐灶定義新字段,在原來字段上能實現(xiàn)嗎?

          其實上面的示例已經(jīng)完美解決問題了,但是再吹毛求疵一下,在原有字段 emotion 上查詢時實現(xiàn)更新值可以嗎?

          實戰(zhàn)一把如下:

          POST?news_00001/_search
          {
          ??"runtime_mappings":?{
          ????"emotion":?{
          ??????"type":?"keyword",
          ??????"script":?{
          ????????"source":?"""
          ?????????if(params._source['emotion']?>?0?&&?params._source['emotion']??????????if(params._source['emotion']?>=?300?&&?params._source['emotion']?<=?700)?{emit('0')}
          ?????????if(params._source['emotion']?>?700?&&?params._source['emotion']?<=?1000)?{emit('1')}
          ????????"""

          ??????}
          ????}
          ??},
          ??"fields":?[
          ????"emotion"
          ??]
          }

          返回結(jié)果:


          解釋一下:

          第一:原來 Mapping 里面 emotion是 integer 類型的。

          第二:我們定義的是檢索時類型,mapping 沒有任何變化,但是:檢索時字段類型 emotion 在字段名稱保持不變的前提下,被修改為:keyword 類型。

          這是一個非常牛逼的功能?。?!

          早期 5.X、6.X 沒有這個功能的時候,實際業(yè)務(wù)中我們的處理思路如下:

          • 步驟一:停掉實時寫入;
          • 步驟二:創(chuàng)建新索引,指定新 Mapping,新增 emotion_flag 字段。
          • 步驟三:恢復(fù)寫入,新數(shù)據(jù)會生效;老數(shù)據(jù) reindex 到新索引,reindex 同時結(jié)合 ingest 腳本處理。

          有了 Runtime?field,這種相當(dāng)繁瑣的處理的“苦逼”日子一去不復(fù)回了!

          5、Runtime fields 適用場景

          比如:日志場景。運行時字段在處理日志數(shù)據(jù)時很有用,尤其是當(dāng)不確定數(shù)據(jù)結(jié)構(gòu)時。

          使用了 runtime field,索引大小要小得多,可以更快地處理日志而無需對其進(jìn)行索引。

          6、Runtime fields 優(yōu)缺點

          優(yōu)點 1:靈活性強(qiáng)

          運行時字段非常靈活。主要體現(xiàn)在:

          • 需要時,可以將運行時字段添加到我們的映射中。

          • 不需要時,輕松刪除它們。

          刪除操作實戰(zhàn)如下:

          PUT?news_00001/_mapping
          {
          ?"runtime":?{
          ???"emotion_flag":?null
          ?}
          }

          也就是說將這個字段設(shè)置為:null,該字段便不再出現(xiàn)在 Mapping 中。

          優(yōu)點 2:打破傳統(tǒng)先定義后使用方式

          運行時字段可以在索引時或查詢時定義。

          由于運行時字段未編入索引,因此添加運行時字段不會增加索引大小,也就是說 Runtime fields 可以降低存儲成本。

          優(yōu)點3:能阻止 Mapping 爆炸

          Runtime field 不被索引(indexed)和存儲(stored),能有效阻止 mapping “爆炸”。

          原因在于 Runtime field 不計算在 ?index.mapping.total_fields 限制里面。

          缺點1:對運行時字段查詢會降低搜索速度

          對運行時字段的查詢有時會很耗費性能,也就是說,運行時字段會降低搜索速度。

          7、Runtime fields 使用建議

          • 權(quán)衡利弊:可以通過使用運行時字段來減少索引時間以節(jié)省 CPU 使用率,但是這會導(dǎo)致查詢時間變慢,因為數(shù)據(jù)的檢索需要額外的處理。

          • 結(jié)合使用:建議將運行時字段與索引字段結(jié)合使用,以便在寫入速度、靈活性和搜索性能之間找到適當(dāng)?shù)钠胶狻?/p>

          8、小結(jié)

          本文通過實戰(zhàn)中添加字段的問題引出解決問題的幾個方案;傳統(tǒng)的解決方案大多都需要更改 Mapping、重建索引、reindex 數(shù)據(jù)等,相對復(fù)雜。

          因而,引申出更為簡單、快捷的 7.11 版本后才有的方案——Runtime?fields。

          Runtime?fields 的核心知識點如下:

          • Mapping 環(huán)節(jié)定義;
          • 在已有 Mapping 基礎(chǔ)上更新
          • 檢索時使用 runtime fields 達(dá)到動態(tài)添加字段的目的;
          • 覆蓋已有 Mapping 字段類型,保證字段名稱一致的情況下,實現(xiàn)特定用途
          • 優(yōu)缺點、適用場景、使用建議。

          你在實戰(zhàn)環(huán)節(jié)使用 Runtime fields 了嗎?效果如何呢?

          歡迎留言反饋交流。

          參考

          https://opster.com/elasticsearch-glossary/runtime-fields/
          https://www.elastic.co/cn/blog/introducing-elasticsearch-runtime-fields
          https://dev.to/lisahjung/beginner-s-guide-understanding-mapping-with-elasticsearch-and-kibana-3646
          https://www.elastic.co/cn/blog/getting-started-with-elasticsearch-runtime-fields

          推薦

          1、重磅 | 死磕 Elasticsearch 方法論認(rèn)知清單(2021年國慶更新版)
          2、Elasticsearch 7.X 進(jìn)階實戰(zhàn)私訓(xùn)課

          短時間快習(xí)得多干貨!

          已帶領(lǐng)70位球友通過 Elastic 官方認(rèn)證!

          中國僅通過百余人

          比同事搶先一步學(xué)習(xí)進(jìn)階干貨!
          瀏覽 52
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲AV成人无码一区二区三区在线观看 | 日本欧美黄色 | 熟女村| 日韩性爱一区 | 香蕉视频色|