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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

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

前言

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

問題

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

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

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

常見場景

場景一

字段類型錯誤:這種情況一般發生在項目初期對業務的預估錯誤或者技術負責人對ES本身不夠了解。

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

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

場景二

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

案例

我們來看下面一個例子,創建以下映射并寫入一條數據:

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

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

以下代碼執行有結果

# 有數據 GET twitter/_search

以下代碼執行無結果

# 無數據 GET twitter/_search {"query": {"term": {"uid": {"value": 1}}} }

痛點及現狀

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

有沒有更好的解決方案 ?

那必須有啊!關注我就對了。

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

案例:

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

假如生產環境我們有如下索引,存儲了一些地震的經緯度以及發生時間和描述等信息:

需求

寫一個查詢滿足以下要求

  • 1:按星期分桶統計地震數據
  • 2:輸出星期一至星期日中平均地震等級 沒有數據的不顯示
  • 3:返回平均地震等級最大的一個 是星期幾
  • 4:進階問題 每個星期的平均地震等級
  • 5:進階問題 平均地震等級最大的是哪個星期
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認證考試出的一道模擬題,在此我們簡化題目,只看前兩個問題

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

面臨的問題

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

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

解決方案:runtime_fields

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

  • 在不重新索引數據的情況下向現有文檔添加字段
  • 在不了解數據結構的情況下開始處理數據
  • 在查詢時覆蓋從索引字段返回的值
  • 為特定用途定義字段而不修改底層架構

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

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

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

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

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:按照周統計地震信息,也就是每周有幾天地震了"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利用運行時字段中執行腳本進行動態計算,從而得出每天分別是一周內的星期幾。這種用法可用于各種其他復雜的運算。

而time字段則是對原有字段進行重新映射,改變其原有字段的類型和其他屬性,如format,使其原本不支持的時間類型變為支持。

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。