Elasticsearch 中存放大量的資料(或稱文件 document)時,一般難以片刻就遍訪每 1 筆資料,如果是為了驗證資料格式,或者需要資料進行實驗,此情況下可選擇用抽樣的方式進行,不僅可利用抽樣的方式預估整個資料庫的情況,也可以有效率地以部分資料進行實驗。

本文記錄如何以 function_score 結合 random_score 進行隨機抽樣。

本文環境

  • Elasticsearch 7.10.1

function_score & random_score

Elasticsearch 預設會將搜尋結果以文件的相關度進行排序,每 1 筆搜尋結果都有 1 個稱為 _score 的欄位,該欄位數值越高代表與搜尋關鍵字的相關度越高,代表越可能是使用者想要的搜尋結果。

但不見得預設的相關度排序方式適合所有類型的資料,因此 Elasticsearch 也提供控制搜尋結果排序的方式,也就是 function_score

function_score 提供若干控制相關度的方式(其它方式詳見文件 ),其中 random_score 可用以隨機為每 1 個文件產生 1 個介於 0 到 1 (不包含 1) 的隨機數作為 _score

如此一來,我們就能夠利用該函式隨機抽樣,例如以下語法隨機抽樣 1 筆資料:

POST /<index>/_search
{
   "query":{
      "function_score":{
         "random_score":{
         }
      }
   },
   "size": 1
}

p.s. 請將 <index> 改為你想要抽樣的 Elasticsearch index 名稱

p.s. 如果需要建立實驗環境,可參考 用 Docker 架設 Elasticsearch 實驗環境 一文

random_score 還可以設定 seed 參數,讓隨機數產生結果可以重現,因此設定 seed 理論上可以每次抽樣到相同的資料,設定 seed 之後仍需要設定 field 參數,告訴 Elasticsearch 以什麼欄位的值產生隨機數值,若不提供的話,預設會以 _id 欄位作為 field 的參數值,但是若以 _id 作為 field 參數值會消耗許多記憶體,若是 production 環境的 Elasticsearch 伺服器,記憶體的異常消耗可能會對服務造成影響,建議可以使用 _seq_no 做為 field 的參數值:

POST /<index>/_search
{
   "query":{
      "function_score":{
         "random_score":{
           "seed": 400,
           "field": "_seq_no"
         }
      }
   },
   "size": 1
}

關於 _seq_no 可以閱讀 Sequence IDs: Coming Soon to an Elasticsearch Cluster Near You 一文,基本上代表每 1 筆資料建立索引時的順序。

值得注意的是,即使設定好 seed 以及 field 仍不能 100% 保證抽樣到相同的資料,因為 Elasticsearch index 仍可能因為資料改變或者進行 merge 等原因造成抽樣結果改變。

更多 radom_score 範例

以下為更多關於 random_score 的範例。

隨機抽樣欄位中含有特定關鍵字的資料

p.s. 請將 <index> , <field><keyword> 改成你想要的值

POST /<index>/_search
{
  "query": {
    "function_score": {
      "query": {
        "bool": {
          "must": [
            {
              "match": {
                "<field>": {
                  "query": "<keyword>"
                }
              }
            }
          ]
        }
      },
      "random_score": {}
    }
  },
  "size": 1
}

結合 filter 隨機抽樣欄位中含有特定關鍵字的資料

p.s. 請將 <index> , <field> , <keyword> , <value> 改成你想要的值

POST /<index>/_search
{
  "query": {
    "function_score": {
      "query": {
        "bool": {
          "must": [
            {
              "match": {
                "<field>": {
                  "query": "<keyword>"
                }
              }
            }
          ],
          "filter": [
            {
              "range": {
                "<field>": {
                  "gte": <value>
                }
              }
            }
          ]
        }
      },
      "random_score": {}
    }
  },
  "size": 1
}

以上為 Elasticsearch 的 random_score 說明。

Happy Coding!

References

https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html#function-random