ようへいの日々精進XP

よかろうもん

Elasticsearch 検索周りTutorial (2) 〜 シェルスクリプトで scroll API を操作する 〜

tl;dr

inokara.hateblo.jp

前回からの続きです. 検索ということではありませんが, 念願のシェルスクリプトで scroll API を利用して検索結果の全件を取得してみました.

Abema TV の番組データが登録されている Elasticsearch

「M 愛すべき人がいて」が既にドキュメントとして登録されていることが判ります.

f:id:inokara:20200621225232p:plain

scroll API を利用して検索結果の全レコードを取得する

シェルスクリプト

以下のようなシェルスクリプトを用意しました.

#!/usr/bin/env bash

# refer to: https://gist.github.com/cb372/4567f624894706c70e65
# require: jq

# 環境に応じて Elasticsearch のエンドポイントとインデックス名を設定する
ES_URL='http://localhost:9200'
INDEX='abema-channel-*'

CMDNAME=$(basename $0)
if [ ! $# -eq 1  ]; then
  echo "Usage: ${CMDNAME} [size]" 1>&2
  exit 1
fi

SIZE=${1}
if [ ${1} -gt 1000 ];then
  echo 'size cannot be more than 1000.'
  exit 1
fi

# ニーズに応じて関数を実装する
function get_title {
  echo ${1} | jq -r .hits.hits[]._source.title
}

echo "=== initial request"
response=$(curl -H "Content-Type: application/json" -s "${ES_URL}/${INDEX}/_search?scroll=1m&size=${SIZE}" -d @query.json)
scroll_id=$(echo ${response} | jq -r ._scroll_id)
hits_count=$(echo ${response} | jq -r '.hits.hits | length')
hits_so_far=hits_count
# echo "Got initial response with ${hits_count} hits and scroll ID ${scroll_id}."

# TODO process first page of results here
get_title "${response}"

i=1
while [ "${hits_count}" != "0" ]; do
  echo "=== request: $i"
  response=$(curl -H "Content-Type: application/json" -s ${ES_URL}/_search/scroll -d "{ \"scroll\": \"1m\", \"scroll_id\": \"$scroll_id\" }")
  scroll_id=$(echo ${response} | jq -r ._scroll_id)
  hits_count=$(echo ${response} | jq -r '.hits.hits | length')
  hits_so_far=$((hits_so_far + hits_count))
  # echo "Got response with ${hits_count} hits (hits so far: ${hits_so_far}), new scroll ID ${scroll_id}."

  # TODO process page of results
  get_title "${response}"

  # DO NOT REMOVE
  i=$(expr $i + 1)
done
echo "Done!"

echo "Remove scroll snapshot."
curl -XDELETE -H "Content-Type: application/json" "${ES_URL}/_search/scroll" -d "
{
    \"scroll_id\" : \"$scroll_id\"
}"

このシェルスクリプトは, 以下のコードを参考にさせて頂きました.

Using the Elasticsearch scroll API · GitHub

シェルスクリプトと一緒に, 以下のような検索クエリ用の JSON ファイル (ファイル名: query.json) を用意します.

{
  "query": {
    "bool": {
      "must": [
        {
          "query_string": {
            "query": "title: \"/愛すべき人\"",
            "analyze_wildcard": true,
            "default_field": "*"
          }
        }
      ]
    }
  }
}

動かしてみる

シェルスクリプトに適当な名前 (今回は scroll.sh ) に設定, 実行権限を付与してシェルスクリプトを実行します.

$ chmod 755 scroll.sh
$ ./scroll.sh 1
=== initial request
M ~愛すべき人がいて~ #1~3ダイジェスト+#4
=== request: 1
M ~愛すべき人がいて~ #1~3ダイジェスト+#4
=== request: 24月新ドラマ】M 愛すべき人がいて #6
=== request: 3
M 愛すべき人がいて / #5 これが神様の答えだ!
=== request: 44月新ドラマ】 #5 これが神様の答えだ! / M 愛すべき人がいて
=== request: 5
【地上波みながらアベマで語ろう!】M 愛すべき人がいて#5※終了後アベマ独占配信
=== request: 6
【地上波みながらアベマで語ろう!】M 愛すべき人がいて#6※終了後アベマ独占配信
=== request: 7
Done!
Remove scroll snapshot.
{"succeeded":true,"num_freed":50}

以上

これまでは, 検索結果を全件取得する際には Python + Elasticsearch ライブラリを用意していましたが, シュッと検索結果が欲しい時に役立ちそうです.

参考

www.elastic.co