Elasticsearch へのドキュメントの登録

BLOG

こんにちは。
サイオステクノロジーの田川です。

今回はインデックスにドキュメントを登録してみたいと思います。

対象者

  • Elastic Cloud のアカウントを持っている人(トライアルライセンスを含む)
  • Elasticsearch の初心者

できるようになること

  • Elastic Cloud の Console から、インデックスにドキュメントを登録する。

前提条件

  • Elastic Cloud (version: 8.15.0)
  • Elastic Cloud 上にインデックスを作成済

(2024年09月25日時点の情報を元に記載しています。)

1. 登録するドキュメントの準備

(Elasticsrearch の “ドキュメント” は、リレーショナルデータベースで言うところの “レコード” のようなものとなります。)

1.1 ドキュメントの登録方法

一般的なドキュメントの登録方法は、大きく分けると2つに分かれます。

  • 1. 1件ずつドキュメントを登録する。
  • 2. Bulk API を利用してドキュメントを複数件まとめて登録する。

(これら以外に、クロールしたWebページ情報を登録する方法などもあります。)

ここでは、2番目の Bulk API を用いて複数件のドキュメントをまとめて登録していきます。

※参考
Bulk API の詳細は下記を参照してください。

Bulk API | Elasticsearch Guide [8.15] | Elastic

なお、Bulk API を呼び出す方法として、

  • Elastic Cloud の Console から実行する方法
  • Pythonなどのプログラミングコードから呼び出す方法

がありますが、ここでは、Elastic Cloud の Console から実行する方法について記載しています。

1.2 登録するドキュメント

このブログ記事内で登録するドキュメントは、「桃太郎」の本文としています。

桃太郎 (楠山 正雄)
一 むかし、むかし、あるところに、おじいさんとおばあさんがありました。まいにち、おじいさんは山へしば刈(か)りに、おばあさんは川へ洗濯(せんたく)に行きました。 ある日、おばあさんが、川のそばで、せっ…

上記の青空文庫の URL から、zip ファイルをダウンロード後、ルビを除去したものを利用しています。
ルビを除去した本文を読み込んで、Bulk API用の入力データに変換しています。

(ファイルの加工方法については、Elasticsearch の話から脱線してしまうので、ここでは詳細は割愛しますが、

下記のような簡単な Python スクリプトで変換しています。)

text2bulk_input.py
-----------------------------------------------------
textfile: str = "./momotaro_no_ruby_utf8.txt"

chunk_no: int = 0
with open(textfile, 'r', encoding="utf-8") as file:
  while True:
    one_line :str = file.readline()
    if one_line == '':
      break

    chunk_no += 1

    # remove last crlf
    content = one_line.replace("\n", "")

    print('{"index": {}}')
    print(f'{{"chunk_no": {chunk_no}, "content": "{content}"}}')

(*脚注1)1

前述の Python スクリプトを実行すると、次のような Bulk API用の入力データが出力されます。

{"index": {}}
{"chunk_no": 1, "content": " むかし、むかし、あるところに、おじいさんとおばあさんがありました。まいにち、おじいさんは..."}
{"index": {}}
{"chunk_no": 2, "content": " ある日、おばあさんが、川のそばで、せっせと洗濯をしていますと、川上から、大きな桃が一つ、"}
...
{"index": {}}
{"chunk_no": 148, "content": " きじはケン、ケンと鳴きながら、くるくると宙返りをしました。"}
{"index": {}}
{"chunk_no": 149, "content": " 空は青々と晴れ上がって、お庭には桜の花が咲き乱れていました。"}

(*脚注2)2

2. ドキュメントの登録(1ドキュメントのみ)

前述で生成された Bulk API用の入力データを Elastic Cloud の Console に貼り付けて実行してみます。

(Elastic Cloud の Console への画面遷移については、前回のブログ記事を参照してください。)

ドキュメントの登録先は、前回作成した momotaro インデックスです。

いきなり全部を貼り付けることはせずに、まずは、最初の2行(1ドキュメント分)のみ貼り付けて実行してみます。

POST /momotaro/_bulk?refresh=true
{"index": {}}
{"chunk_no": 1, "content": " むかし、むかし、あるところに、おじいさんとおばあさんがありました。まいにち、おじいさんは..."}

(*脚注3)3

ドキュメントの登録に成功したら、次のような結果がレスポンスに表示されます。

{
  "errors": false,
  "took": 26734000762,
  "items": [
    {
      "index": {
        "_index": "momotaro",
        "_id": "*****************",
        "_version": 1,
        "result": "created",
        "_shards": {
          "total": 2,
          "successful": 1,
          "failed": 0
        },
        "_seq_no": 0,
        "_primary_term": 1,
        "status": 201
      }
    }
  ]
}

上記の “_id” は、リレーショナルデータベースで言うところの主キーに該当します。

さきほどの POST メソッドにより、Elasticsearch 側で自動採番されます。

3. 登録されたドキュメントの確認

Elastic Cloud の Console から次のようなリクエストを発行してみます。

GET /momotaro/_search

すると、次のような結果が返ってきます。

{
  "took": 0,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 1,
    "hits": [
      {
        "_index": "momotaro",
        "_id": ""*****************",
        "_score": 1,
        "_source": {
          "chunk_no": 1,
          "content": " むかし、むかし、あるところに、おじいさんとおばあさんが...(以降省略)..."
        }
      }
    ]
  }
}

※ _search の response の詳細については、下記を参照してください。

Search API | Elasticsearch Guide [8.15] | Elastic

1件のドキュメントが登録され、検索できるようになっていることが確認できました。

インデックスの Overview をクリックしてみます。

Document count が 1 になっていることがわかります。

インデックスの Documents をクリックしてみます。

さきほど登録したドキュメントが表示されています。

4. 残りのドキュメントの登録

chunk_no : 2 ~ 149 の本文を Console から Bulk API を使って登録します。

POST /momotaro/_bulk?refresh=true
{"index": {}}
{"chunk_no": 2, "content": " ある日、おばあさんが、川のそばで、せっせと洗濯をしていますと、川上から、大きな桃が一つ、"}
{"index": {}}
{"chunk_no": 3, "content": "「ドンブラコッコ、スッコッコ。"}
...
{"index": {}}
{"chunk_no": 148, "content": " きじはケン、ケンと鳴きながら、くるくると宙返りをしました。"}
{"index": {}}
{"chunk_no": 149, "content": " 空は青々と晴れ上がって、お庭には桜の花が咲き乱れていました。"}

momotaro インデックスのOverviewを確認すると、
Document count = 149 となっていることがわかります。

今回は149件という比較的少ないデータ量だったので、Console への貼り付けでドキュメントの登録を行いましたが、もっと大量にある場合や、外部のファイルなどからプログラムでテキストを読み込んで登録したい場合などは、Pythonなどのプログラムからドキュメントを登録する方法が向いています。
(Pythonからの呼び出しについては、後日、説明予定です。)

次回は、登録したドキュメントを検索してみたいと思います。


(*脚注)

  1. Elasticsearchの1つのドキュメントに、どのような単位で登録するか?というのは、検索精度における課題の一つとなります。
    検索システムで扱う本番用データであれば、どのように分割するか?は、慎重に検討すべき問題です。
    例)
    ・一定の文字数で区切って登録する。
    ・一文ずつ登録する。
    ・”。”で区切って登録する。
    ・意味的な塊ごとに登録する。
    また、前後のドキュメント(いわゆるチャンク)との重複をどの程度にするか?も調整が難しいポイントになります。
    今回は、検索できればいい、というシンプルなサンプルデータですので、元のデータで「一文」に区切られている部分を、そのまま「1つのドキュメント」として登録しています。
    ↩︎
  2. ここでの Bulk API用の入力データでは、”_id”を指定していません。
    Elasticsearch への登録時に自動的に”_id”が割り振られます。

    Bulk API を利用してドキュメントを登録したり、あるいは、1件ずつドキュメントを登録する場合に、
    “_id” を指定して登録することも可能と言えば可能ですが、推奨いたしません。

    “_id” を指定して新規登録する場合、Elasticsearch 側で “_id” が重複していないか?といったチェックが
    働くことになり、ドキュメントの登録にかかる時間が長くなります。

    どうしても “_id” を指定しなければならない特別な場合を除いては、”_id” は指定しないことをお勧めします。
    ↩︎
  3. インデックスのリフレッシュ間隔を短い時間にしている場合は、refresh=true を指定しなくても検索できるようになりますが、前回のブログ記事内で refresh_interval = 3600s としているため、refresh を明示的に行う必要があります。 ↩︎