<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 的基數(shù)統(tǒng)計(jì)在大數(shù)據(jù)量下有什么辦法能做到 100% 準(zhǔn)確度嗎?

          共 7967字,需瀏覽 16分鐘

           ·

          2024-06-19 07:30

          球友提問:Elasticsearch 的基數(shù)統(tǒng)計(jì)在大數(shù)據(jù)量下有什么辦法能做到 100% 準(zhǔn)確度嗎?

          https://t.zsxq.com/VYDcW

          在Elasticsearch中,基數(shù)統(tǒng)計(jì)(如基數(shù)聚合)在大數(shù)據(jù)量下通常使用 HyperLogLog++算法,該算法是近似算法,因此會(huì)有一定誤差。

          1、構(gòu)造 100萬條數(shù)據(jù)

          我這邊隨機(jī)構(gòu)造了 100萬條記錄寫入 Elasticsearch 以便測(cè)試。

          先說一下構(gòu)造代碼的邏輯:

          隨機(jī)生成代碼生成大量隨機(jī)中文數(shù)據(jù),并將其批量導(dǎo)入到Elasticsearch索引中。通過循環(huán)創(chuàng)建包含隨機(jī)中文詞匯和隨機(jī)整數(shù)的文檔,每批生成2000個(gè)文檔就使用Elasticsearch的 bulk API進(jìn)行批量導(dǎo)入,以提高導(dǎo)入效率,直到所有指定數(shù)量的文檔全部導(dǎo)入完成。

          導(dǎo)入 Elasticsearch 后的結(jié)果如下圖所示。

          數(shù)據(jù)樣例如下圖所示。

          為了方便真實(shí)統(tǒng)計(jì)結(jié)果,我這邊又借助 scroll 將 寫入 Elasticsearch 的文本導(dǎo)出到 out_title.txt 文件。

          最終用如下腳本去重后的結(jié)果為:632483 條。

          Elasticsearch 如果需要100%的準(zhǔn)確度,可以考慮以下幾種解決方案。

          先做驗(yàn)證,最后說結(jié)論。

          1. 方案1:使用相對(duì)“精準(zhǔn)”的cardinality基數(shù)聚合

          構(gòu)造索引 test_index_0618 的映射結(jié)構(gòu)如下所示:

          {
            "test_index_0618": {
              "mappings": {
                "properties": {
                  "id": {
                    "type""integer"
                  },
                  "title": {
                    "type""text",
                    "fields": {
                      "keyword": {
                        "type""keyword"
                      }
                    },
                    "analyzer""ik_max_word"
                  }
                }
              }
            }
          }

          Elasticsearch從7.10版本開始引入了 cardinality 聚合的 precision_threshold 參數(shù),當(dāng)設(shè)置為較高的值時(shí),可以提供更準(zhǔn)確的基數(shù)統(tǒng)計(jì)。

          https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-cardinality-aggregation.html

          配置方法:

          POST test_index_0618/_search
          {
            "aggs": {
              "unique_count": {
                "cardinality": {
                  "field""title.keyword",
                  "precision_threshold": 40000
                }
              }
            }
          }

          precision_threshold 選項(xiàng)在Elasticsearchcardinality聚合中,用于在內(nèi)存消耗和計(jì)數(shù)準(zhǔn)確性之間進(jìn)行平衡。 

          設(shè)置該值可以控制在多少唯一值以下時(shí)計(jì)數(shù)結(jié)果非常準(zhǔn)確,而超過該值時(shí)計(jì)數(shù)結(jié)果可能會(huì)稍有誤差。

          最大支持的值為40000,超過該值將沒有額外效果,默認(rèn)情況下,這個(gè)閾值設(shè)為3000。

          但對(duì)比真實(shí)去重結(jié)果:632483 條,會(huì)有接近 633011-632483=多出528大小的偏差。

          2. 方案2:使用terms聚合結(jié)合 cardinality基數(shù)統(tǒng)計(jì)

          如下查詢通過terms聚合獲取title.keyword字段的前10000個(gè)唯一值,并使用cardinality聚合計(jì)算該字段的唯一值總數(shù)。

          實(shí)操方法:

          {
            "size": 0,
            "aggs": {
              "unique_values": {
                "terms": {
                  "field""title.keyword",
                  "size": 10000
                }
              },
              "unique_count": {
                "cardinality": {
                  "field""title.keyword"
                }
              }
            }
          }

          在terms 聚合中設(shè)置足夠大的size,以覆蓋所有可能的唯一值。

          結(jié)果值依然不是精準(zhǔn)值,會(huì)有 632483-631915= 568 大小的偏差。

          但是分桶值足夠大也不能非常大,否則會(huì)報(bào)錯(cuò),因?yàn)槿笔≈凳?65536。側(cè)面印證,如果聚合結(jié)果值查過65536 會(huì)不精確。

          {
            "error": {
              "root_cause": [],
              "type""search_phase_execution_exception",
              "reason""",
              "phase""fetch",
              "grouped"true,
              "failed_shards": [],
              "caused_by": {
                "type""too_many_buckets_exception",
                "reason""Trying to create too many buckets. Must be less than or equal to: [65536] but this number of buckets was exceeded. This limit can be set by changing the [search.max_buckets] cluster level setting.",
                "max_buckets": 65536
              }
            },
            "status": 400
          }

          獲取 search.max_buckets 值:

          GET /_cluster/settings?include_defaults=true&filter_path=defaults.search.max_buckets

          我們把 search.max_buckets 調(diào)整到和數(shù)據(jù)量一致:

          PUT /_cluster/settings
          {
            "persistent": {
              "search.max_buckets": 1000000
            }
          }

          執(zhí)行會(huì)報(bào)錯(cuò):

          猜測(cè)就是數(shù)據(jù)量太大,處理不過來!

          我把分桶大小改成 700000 后,可以執(zhí)行,但結(jié)果依然不是精準(zhǔn)值。

          POST test_index_0618/_search
          {
            "size": 0,
            "aggs": {
              "unique_values": {
                "terms": {
                  "field""title.keyword",
                  "size": 700000
                }
              },
              "unique_count": {
                "cardinality": {
                  "field""title.keyword"
                }
              }
            }
          }

          結(jié)果比真實(shí)結(jié)果值依然是有出入,多了 635954- 632483=3471。

          3. 方案3:分區(qū)統(tǒng)計(jì)和匯總

          如果數(shù)據(jù)量非常大,可以考慮將數(shù)據(jù)分片(按時(shí)間、地理位置等字段分區(qū)),在各個(gè)分區(qū)內(nèi)分別進(jìn)行基數(shù)統(tǒng)計(jì),然后匯總各個(gè)分區(qū)的結(jié)果。

          步驟1:將數(shù)據(jù)按某個(gè)字段進(jìn)行分區(qū)(如時(shí)間)。

          步驟2:對(duì)每個(gè)分區(qū)分別進(jìn)行基數(shù)統(tǒng)計(jì)。

          步驟3:匯總所有分區(qū)的基數(shù)統(tǒng)計(jì)結(jié)果。

          這其實(shí)是借助分而治之的算法思想來求解。

          但,由于咱們的構(gòu)造數(shù)據(jù)字段受限,該方案我沒有求證。

          4. 方案4:借助外部工具如 redis 實(shí)現(xiàn)

          該方案是將 Elasticsearch 數(shù)據(jù)同步遷移到 redis,借助 redis 實(shí)現(xiàn)的聚合統(tǒng)計(jì)。

          def export_to_redis(es, redis_client, index_name):    try:        # 清空Redis Set        redis_client.delete("unique_values")
          # Scroll API 獲取所有數(shù)據(jù) scroll_size = 1000 data = es.search(index=index_name, body={"query": {"match_all": {}}}, scroll='2m', size=scroll_size) scroll_id = data['_scroll_id'] total_docs = data['hits']['total']['value']
          print(f"Total documents to process: {total_docs}")
          while scroll_size > 0: for doc in data['hits']['hits']: field_value = doc['_source']['title'] redis_client.sadd("unique_values", field_value)
          data = es.scroll(scroll_id=scroll_id, scroll='2m') scroll_id = data['_scroll_id'] scroll_size = len(data['hits']['hits'])
          unique_count = redis_client.scard("unique_values") print(f"Unique values count: {unique_count}")
          # 清理scroll上下文 es.clear_scroll(scroll_id=scroll_id)
          except redis.RedisError as e: print(f"Redis error: {e}") except Exception as e: print(f"Unexpected error: {e}")

          借助 redis 實(shí)現(xiàn),寫入后統(tǒng)計(jì)實(shí)現(xiàn)如下:

          unique_count = redis_client.scard("unique_values")

          上述代碼作用是獲取Redis集合unique_values中的唯一元素?cái)?shù)量。它利用了Redis集合的去重特性,通過scard方法返回集合中元素的總數(shù)。去重后結(jié)果如下:

          借助 redis 客戶端查看結(jié)果也和統(tǒng)計(jì)結(jié)果一致。

          5. 小結(jié)

          為了在大數(shù)據(jù)量下實(shí)現(xiàn)100%準(zhǔn)確的基數(shù)統(tǒng)計(jì),可以結(jié)合以下思路和方法:

          提高precision_threshold參數(shù)。使用terms聚合結(jié)合bucket selector。分區(qū)統(tǒng)計(jì)和匯總。借助外部大數(shù)據(jù)處理工具(如 redis)進(jìn)行統(tǒng)計(jì)。

          這些方法各有優(yōu)缺點(diǎn),具體選擇可以根據(jù)實(shí)際的業(yè)務(wù)需求、數(shù)據(jù)規(guī)模和系統(tǒng)性能來決定。

          實(shí)操驗(yàn)證發(fā)現(xiàn)基于 Elasticsearch 統(tǒng)計(jì)幾乎沒法實(shí)現(xiàn)精準(zhǔn)去重結(jié)果。

          在實(shí)際應(yīng)用中,可能需要綜合運(yùn)用多種方法,以達(dá)到既滿足性能要求又保證統(tǒng)計(jì)準(zhǔn)確度的目的。


          2024星球?qū)O恚?/span>Elastic 8.1 認(rèn)證全部知識(shí)點(diǎn) 腦圖 + 視頻

          https://articles.zsxq.com/id_njwt7kus4r42.html 

          新時(shí)代寫作與互動(dòng):《一本書講透 Elasticsearch》讀者群的創(chuàng)新之路


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

          和全球2000+ Elastic 愛好者一起精進(jìn)!

          elastic6.cn——ElasticStack進(jìn)階助手


          比同事搶先一步學(xué)習(xí)進(jìn)階干貨!

          瀏覽 100
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  国产专区在线播放 | 无码三级乱伦 | 天天操天天狠 | 婷婷激情丁香花 | www.色综合 |