日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

不必Reindex,利用runtime_fields优雅地解决字段类型错误问题

發(fā)布時間:2023/12/20 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 不必Reindex,利用runtime_fields优雅地解决字段类型错误问题 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

前言

作為程序員入職一家新公司,當(dāng)你看到前任程序員寫的代碼的時候,你是不是經(jīng)常有這樣的感覺:我屮艸芔茻!這代碼真他喵的爛!

問題

對于程序員來說,代碼水平良莠不齊比較常見的事情,之所以代碼質(zhì)量不高,一方面原因是自身不太關(guān)注于代碼的整體管理,另一方面原因是經(jīng)驗不足。實際上在處理公司業(yè)務(wù)的時候,這種前人挖坑,后人填坑的事情時有發(fā)生。

對,我們今天暫時不討論代碼規(guī)范的問題,而是說一說,再處理搜索業(yè)務(wù)的時候,如果你已經(jīng)接手了一些無法描述的代碼,咱們怎么補救。

首先對于任何問題而言,預(yù)防問題發(fā)生永遠(yuǎn)勝于問題發(fā)生之后再對其進(jìn)行補救,這是一定的。不過既然問題已經(jīng)發(fā)生,我們就只能以最小代價或者針對自身情況選擇處理方式,比如,我們可以選擇是先治標(biāo)還是先治本,最主要區(qū)別在于見效速度。下面我們分別來說一下這兩種解決方案的區(qū)別和適用場景:

常見場景

場景一

字段類型錯誤:這種情況一般發(fā)生在項目初期對業(yè)務(wù)的預(yù)估錯誤或者技術(shù)負(fù)責(zé)人對ES本身不夠了解。

很多人都知道,為了優(yōu)化性能,可以適當(dāng)縮減字段屬性。比如確定不需要聚合或者排序的字段,可對其關(guān)閉正排索引,不需要對其進(jìn)行檢索的字段可關(guān)閉倒排索引,不需要評分的字段可以關(guān)閉評分功能以此可節(jié)約字段存儲空間,提高效率。

另外一種情況是在創(chuàng)建索引的時候,對ES的字段本身不夠了解,比如之前我們提到的“yyyy-MM-dd HH:mm:ss”這種格式并非默認(rèn)支持的時間類型,如果一開始技術(shù)員并不知道,而將數(shù)據(jù)直接寫入,有可能的結(jié)果就是,時間總段存儲成為了“text”類型,而給后期埋下隱患。

場景二

上述問題是字段類型錯誤,還有一種情況是針對于數(shù)據(jù)本身。比如:當(dāng)我們某個索引報錯了不同來源或渠道的數(shù)據(jù),每個渠道可能采集數(shù)據(jù)負(fù)責(zé)的程序員并不相同,最常見的情況比如,我們采集用戶行為日志,需要涉及“APP”、“Web”、“PC”、“小程序”等來源,可能負(fù)責(zé)開發(fā)的程序員分別來自不同的部門,如果在最開始沒有最好約定,可能就會出現(xiàn)字段或者單位不統(tǒng)一或者一些列其他問題。總之就是協(xié)調(diào)發(fā)生問題而導(dǎo)致數(shù)據(jù)不統(tǒng)一。這也給后期做數(shù)據(jù)分析或者統(tǒng)計造成很大影響。

案例

我們來看下面一個例子,創(chuàng)建以下映射并寫入一條數(shù)據(jù):

PUT twitter {"mappings": {"properties": {"uid": {"enabled": false}}} } POST twitter/_doc {"uid": "1" }

以上代碼為我們在項目初期,負(fù)責(zé)人對將來業(yè)務(wù)的預(yù)估是不會出現(xiàn)通過uid 進(jìn)行檢索的情況,因此錯誤的把此字段的enabled 設(shè)置為了false, 此時數(shù)據(jù)將不能通過此字段進(jìn)行檢索。注意是不能通過此字段檢索而不是不能將此字段檢索出來,只是沒有創(chuàng)建索引而非刪除了元數(shù)據(jù)。具體體現(xiàn)為:下面代碼第一行執(zhí)行有數(shù)據(jù),第二行無數(shù)據(jù)。

以下代碼執(zhí)行有結(jié)果

# 有數(shù)據(jù) GET twitter/_search

以下代碼執(zhí)行無結(jié)果

# 無數(shù)據(jù) GET twitter/_search {"query": {"term": {"uid": {"value": 1}}} }

痛點及現(xiàn)狀

后期經(jīng)過業(yè)務(wù)的發(fā)展和迭代,逐漸發(fā)現(xiàn)了此字段無法檢索的問題,而很多公司的選擇都是Reindex,的確,重建索引可以解決很多問題,但是這樣未來過于“勞師動眾!”,因為基本上ES的應(yīng)用場景都是基于海量數(shù)據(jù)的索引,重建索引可能耗費大量時間,無異于殺雞取卵,得不償失。

有沒有更好的解決方案 ?

那必須有啊!關(guān)注我就對了。

同類問題還包括如之前提到的,“yyyy-MM-dd HH:mm:ss”而導(dǎo)致的類型不匹配問題,在處理此一類問題時,皆可采用runtime_fields來解決。

案例:

我們沿用之前“yyyy-MM-dd HH:mm:ss 是時間類型?別再錯下去了!”提到的不是時間類型導(dǎo)致的錯誤的案例,如果沒看過之前的文章,戳:傳送門

假如生產(chǎn)環(huán)境我們有如下索引,存儲了一些地震的經(jīng)緯度以及發(fā)生時間和描述等信息:

需求

寫一個查詢滿足以下要求

  • 1:按星期分桶統(tǒng)計地震數(shù)據(jù)
  • 2:輸出星期一至星期日中平均地震等級 沒有數(shù)據(jù)的不顯示
  • 3:返回平均地震等級最大的一個 是星期幾
  • 4:進(jìn)階問題 每個星期的平均地震等級
  • 5:進(jìn)階問題 平均地震等級最大的是哪個星期
POST task1/_bulk?refresh=true {"index":{}} {"time":"2011-06-16 12:12:21","magnitude" : 1.4, "lon" : -116.0902, "lat" : 33.2253, "depth" : 9.98, "area" : " 10km NNE of Ocotillo Wells"} {"index":{}} {"time":"2011-06-16 12:12:21","magnitude" : 1.3, "lon" : -116.0902, "lat" : 33.2253, "depth" : 9.98, "area" : " 10km NNE of Ocotillo Wells"} {"index":{}} {"time":"2011-06-17 12:12:21","magnitude" : 1.5, "lon" : -116.0902, "lat" : 33.2253, "depth" : 9.98, "area" : " 10km NNE of Ocotillo Wells"} {"index":{}} {"time":"2011-04-18 12:12:21","magnitude" : 1.6, "lon" : -116.0902, "lat" : 33.2253, "depth" : 9.98, "area" : " 10km NNE of Ocotillo Wells"} {"index":{}} {"time":"2011-06-19 12:12:21","magnitude" : 1.9, "lon" : -116.0902, "lat" : 33.2253, "depth" : 9.98, "area" : " 10km NNE of Ocotillo Wells"} {"index":{}} {"time":"2011-06-20 12:12:21","magnitude" : 2.0, "lon" : -116.0902, "lat" : 33.2253, "depth" : 9.98, "area" : " 10km NNE of Ocotillo Wells"} {"index":{}} {"time":1308544245123,"magnitude" : 2.1, "lon" : -116.0902, "lat" : 33.2253, "depth" : 9.98, "area" : " 10km NNE of Ocotillo Wells"} {"index":{}} {"time":1308717045123,"magnitude" : 2.8, "lon" : -116.0902, "lat" : 33.2253, "depth" : 9.98, "area" : " 10km NNE of Ocotillo Wells"} {"index":{}} {"time":"2011-06-20 12:12:21","magnitude" : 2.9, "lon" : -116.0902, "lat" : 33.2253, "depth" : 9.98, "area" : " 10km NNE of Ocotillo Wells"} {"index":{}} {"time":"2011-06-20 12:12:21","magnitude" : 3.3, "lon" : -116.0902, "lat" : 33.2253, "depth" : 9.98, "area" : " 10km NNE of Ocotillo Wells"}

這是我為Elastic認(rèn)證考試出的一道模擬題,在此我們簡化題目,只看前兩個問題

但是,因為不可描述的原因,time字段有的數(shù)據(jù)存儲成為了yyyy-MM-dd HH:mm:ss,有的存儲成為了時間戳,最終time字段的類型并沒有像預(yù)想的那樣為date類型他們可能來自于同一個公司的不同部門,所以導(dǎo)致了這種問題。

面臨的問題

此時,面對上述需求,存在兩個問題

  • time字段為text而非date類型,而導(dǎo)致我們無法使用日期時間類型的所有函數(shù)。
  • 數(shù)據(jù)存儲的格式不統(tǒng)一,有時間戳,有"yyyy-MM-dd HH:mm:ss",無法統(tǒng)一計算。

解決方案:runtime_fields

運行時字段是在執(zhí)行查詢時動態(tài)對字段類型和索引重新定義的字段。runtime_fields具備以下特點:

  • 在不重新索引數(shù)據(jù)的情況下向現(xiàn)有文檔添加字段
  • 在不了解數(shù)據(jù)結(jié)構(gòu)的情況下開始處理數(shù)據(jù)
  • 在查詢時覆蓋從索引字段返回的值
  • 為特定用途定義字段而不修改底層架構(gòu)

由于運行時字段未編入索引,因此添加運行時字段不會增加索引大小。直接在索引映射中定義運行時字段,可以節(jié)省存儲成本并提高預(yù)處理速度。

如果將運行時字段設(shè)為索引字段,則無需修改任何引用運行時字段的查詢。而且可以引用字段是運行時字段的一些索引,以及字段是索引字段的其他索引。可以靈活地選擇要索引哪些字段以及保留哪些字段作為運行時字段。

就其核心而言,運行時字段最重要的好處是能夠在提取文檔后將字段添加到文檔中。此功能簡化了映射決策,所以不需要預(yù)先決定如何解析數(shù)據(jù),并且可以使用運行時字段隨時修改映射。使用運行時字段索引更小且更快的預(yù)處理信息,這結(jié)合使用更少的資源并降低運營成本。

上述問題,解決方案代碼如下:

GET task1/_search {"size": 0,"runtime_mappings": {"day_of_week": {"type": "keyword","script": "emit(doc['time'].value.dayOfWeekEnum.getDisplayName(TextStyle.FULL,Locale.ROOT))"},"time": {"type": "date","format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"}},"aggs": {//1:按照周統(tǒng)計地震信息,也就是每周有幾天地震了"week_agg": {"date_histogram": {"field": "time","calendar_interval": "week"},"aggs": {"week_avg_magnitude": {"avg": {"field": "magnitude"}}}},//一周中的每一天的震級"day_of_week_magnitude":{"terms": {"field": "day_of_week"},"aggs": {//2: 一周中每一天的平均地震等級"day_of_week_avg_magnitude": {"avg": {"field": "magnitude"}}}}} }

此段代碼中,其核心代碼如下

"runtime_mappings": {"day_of_week": {"type": "keyword","script": "emit(doc['time'].value.dayOfWeekEnum.getDisplayName(TextStyle.FULL,Locale.ROOT))"},"time": {"type": "date","format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"}}

其在runtime_mappings 中定義了兩個“新字段”,即day_of_week和time,其中day_of_week利用運行時字段中執(zhí)行腳本進(jìn)行動態(tài)計算,從而得出每天分別是一周內(nèi)的星期幾。這種用法可用于各種其他復(fù)雜的運算。

而time字段則是對原有字段進(jìn)行重新映射,改變其原有字段的類型和其他屬性,如format,使其原本不支持的時間類型變?yōu)橹С帧?/p>

總結(jié)

以上是生活随笔為你收集整理的不必Reindex,利用runtime_fields优雅地解决字段类型错误问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。