Docker 入門
Elasticsearch で全文検索を実行する(macOS版)
ドキュメントの登録・更新・削除と簡単な検索
いよいよ Elasticsearch にドキュメントを登録し,様々な全文検索を行います.準備作業として GitHub で公開している「小倉百人一首」の100個の JSON ファイルをダウンロードし hyaku_data ディレクトリ以下に設置しておいてください.
まず,登録したいドキュメントを確認します.100個 のJSON ファイルが hyaku_data ディレクトリに存在することを確認してください.1個目のファイルは次のような内容です.
hyaku_data/001.json
{
"id": "1",
"uta": "秋の田の かりほの庵の 苫をあらみ わが衣手は 露にぬれつつ",
"kana": "あきのたの かりほのいほの とまをあらみ わがころもでは つゆにぬれつつ",
"kajin": "天智天皇"
}
また,シェル変数に API キーが読み込まれていることを確認します.
elastic-start-local % echo ${ES_LOCAL_API_KEY} ⏎
Q25EX3RKb0I3SzJUQjVKNm8xQXQ6OXcxT3phdlhVV1BIeEhVZXh1clJMZw==
elastic-start-local %
まだ読み込まれていなければ次のコマンドを実行してファイル .env からシェル変数に読み込みます.
elastic-start-local % source .env ⏎
elastic-start-local %
ドキュメントの登録
ドキュメントの登録コマンドは次のとおりで,登録先は /hyaku_index/_doc/です.ここで,登録したいファイルを -d @ディレクトリ名/ファイル名 オプションで指定していることに注意してください.同時に,リクエストの本文が JSON 形式のデータであることから,そのことを伝えるために -H "Content-type: application/json" というオプションも付与する必要があります.(実はインデックスの生成などでもこのオプションを使っていました.),登録時には自動的に ID (具体的には _id)が付与されます.
curl -X POST -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" -H "Content-type: application/json" -d @hyaku_data/001.json "http://localhost:9200/hyaku_index/_doc"
一方で,curl のバージョン 7.82.0 以降であれば,--json オプションが利用できます.このオプションを利用すると,Content-Type: application/json と Accept: application/json を自動で付けてくれます.
curl -X POST -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" --json @hyaku_data/001.json "http://localhost:9200/hyaku_index/_doc"
実際にコマンドを実行します.登録が成功して自動的に付与された _id フィールドの値が表示されていることに注意してください.
elastic-start-local % curl -X POST -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" --json @hyaku_data/001.json "http://localhost:9200/hyaku_index/_doc" ⏎ {"_index":"hyaku_index","_id":"yAdmw5oB41J4chRllnaO","_version":1,"result":"created","_shards":{"total":1,"successful":1,"failed":0},"_seq_no":0,"_primary_term":1}% elastic-start-local %
上の結果は少し読み取りにくいため,今度は pretty オプションを付与して別のドキュメントを登録します.
curl -X POST -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" --json @hyaku_data/002.json "http://localhost:9200/hyaku_index/_doc?pretty"
上のコマンドを実際に実行します.オプションを付与したことで出力結果が見やすくなりました
elastic-start-local % curl -X POST -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" --json @hyaku_data/002.json "http://localhost:9200/hyaku_index/_doc?pretty" ⏎
{
"_index" : "hyaku_index",
"_id" : "yQdnw5oB41J4chRlJHZ0",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 1,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 1,
"_primary_term" : 1
}
elastic-start-local %
残りの98件のドキュメントをまとめて実行します.(ぜひこのあたりを参考にスクリプトを作成してコマンド1発ですべてのドキュメントが登録できるように考えてください.)
curl -X POST -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" --json @hyaku_data/003.json "http://localhost:9200/hyaku_index/_doc?pretty"
curl -X POST -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" --json @hyaku_data/004.json "http://localhost:9200/hyaku_index/_doc?pretty"
...(中略)...
curl -X POST -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" --json @hyaku_data/099.json "http://localhost:9200/hyaku_index/_doc?pretty"
curl -X POST -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" --json @hyaku_data/100.json "http://localhost:9200/hyaku_index/_doc?pretty"
すでにここで説明したドキュメントの登録件数を確認するコマンドです.
curl -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" "http://localhost:9200/hyaku_index/_count?pretty"
実際に実行します.登録済みドキュメントが100件あることが分かりました.
elastic-start-local % curl -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" "http://localhost:9200/hyaku_index/_count?pretty" ⏎ { "count" : 100, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 } } elastic-start-local %
件数を限定してドキュメントを取得
よく実行するであろう検索内容は JSON ファイルに保存しておき,それを実行すると良いでしょう.具体的には次の list_ids.json ファイルを準備します.次の JSON ファイルでは取得する件数を指定していませんが,Elasticsearch では大量のデータを格納することを念頭に置いている関係で,取得件数を指定しなければ10件のドキュメントだけが表示されることになります.
json/list_ids.json
{
"_source": false,
"query": {
"match_all": {}
}
}
検索のコマンドは /hyaku_index/_search にリクエストします.
curl -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" --json @json/list_ids.json "http://localhost:9200/hyaku_index/_search?pretty"
実際に上のコマンドを実行すると次のような結果が得られました.具体的には合計 100 件のドキュメントがあり,そのうち検索スコア (_score) 順に10件の _id などが表示されています.ただし,キーワード検索ではなく一覧表示であるのですべてのスコアが 1.0 になっています.
elastic-start-local % curl -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" --json @json/list_ids.json "http://localhost:9200/hyaku_index/_search?pretty" ⏎ { "took" : 0, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 100, "relation" : "eq" }, "max_score" : 1.0, "hits" : [ { "_index" : "hyaku_index", "_id" : "yAdmw5oB41J4chRllnaO", "_score" : 1.0 }, { "_index" : "hyaku_index", "_id" : "yQdnw5oB41J4chRlJHZ0", "_score" : 1.0 }, { "_index" : "hyaku_index", "_id" : "ygdow5oB41J4chRlTHYc", "_score" : 1.0 }, { "_index" : "hyaku_index", "_id" : "ywdow5oB41J4chRlTHY1", "_score" : 1.0 }, { "_index" : "hyaku_index", "_id" : "zAdow5oB41J4chRlTHZL", "_score" : 1.0 }, { "_index" : "hyaku_index", "_id" : "zQdow5oB41J4chRlTHZg", "_score" : 1.0 }, { "_index" : "hyaku_index", "_id" : "zgdow5oB41J4chRlTHZy", "_score" : 1.0 }, { "_index" : "hyaku_index", "_id" : "zwdow5oB41J4chRlTHaE", "_score" : 1.0 }, { "_index" : "hyaku_index", "_id" : "0Adow5oB41J4chRlTHaW", "_score" : 1.0 }, { "_index" : "hyaku_index", "_id" : "0Qdow5oB41J4chRlTHao", "_score" : 1.0 } ] } } elastic-start-local %
取得するサイズを変更したい場合は次のとおり size を指定します.
{
"_source": false,
"query": {
"match_all": {}
},
"size": 100
}
検索コマンドは次のとおりですが,JSON ファイルへのパス名が変わっただけです.
curl -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" --json @json/list_ids_100.json "http://localhost:9200/hyaku_index/_search?pretty"
実際にコマンドを実行すると 100 件の情報を取得できました.(長いので表示は省略しています.)
elastic-start-local % curl -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" --json @json/list_ids_100.json "http://localhost:9200/hyaku_index/_search?pretty" ⏎ { "took" : 2, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 100, "relation" : "eq" }, "max_score" : 1.0, "hits" : [ { "_index" : "hyaku_index", "_id" : "yAdmw5oB41J4chRllnaO", "_score" : 1.0 }, ...(中略)... { "_index" : "hyaku_index", "_id" : "0Qdow5oB41J4chRlTHao", "_score" : 1.0 }, ...(中略)... { "_index" : "hyaku_index", "_id" : "Kwdow5oB41J4chRlUne3", "_score" : 1.0 } ] } } elastic-start-local %
個別データの取得
個別データを取得するには _id を指定します.この _id はドキュメントを登録した際に表示されます.その他検索した際にも確認できます.例えば,10件目のデータである _id = "0Qdow5oB41J4chRlTHao" のドキュメントを取得するには次のようなコマンドを準備します.
curl -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" "http://localhost:9200/hyaku_index/_doc/0Qdow5oB41J4chRlTHao?pretty"
実際に上のコマンドを実行した結果を示します.
elastic-start-local % curl -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" "http://localhost:9200/hyaku_index/_doc/0Qdow5oB41J4chRlTHao?pretty" ⏎
{
"_index" : "hyaku_index",
"_id" : "0Qdow5oB41J4chRlTHao",
"_version" : 1,
"_seq_no" : 9,
"_primary_term" : 1,
"found" : true,
"_source" : {
"id" : "10",
"uta" : "これやこの 行くも帰るも 別れては 知るも知らぬも あふ坂の関",
"kana" : "これやこの ゆくもかへるも わかれては しるもしらぬも あふさかのせき",
"kajin" : "蟬丸"
}
}
elastic-start-local %
データの検索
次に "uta" のフィールドについての全文検索を行います.例えば「雪」という単語が含まれるドキュメントを検索したい場合は次のような JSON ファイルを準備します.
json/search_yuki.json
{
"query": {
"match": {
"uta": "雪"
}
}
}
検索するにはやはり -d オプションで JSON ファイルのパスを指定します.
curl -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" --json @json/search_yuki.json "http://localhost:9200/hyaku_index/_search?pretty"
実際にコマンドを実行すると次の結果が得られました.4件のドキュメントが検索され,検索スコア (_score) の高い順に表示されていることが分かります.
elastic-start-local % curl -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" --json @json/search_yuki.json "http://localhost:9200/hyaku_index/_search?pretty" ⏎ { "took" : 2, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 4, "relation" : "eq" }, "max_score" : 3.1701806, "hits" : [ { "_index" : "hyaku_index", "_id" : "ywdow5oB41J4chRlTHY1", "_score" : 3.1701806, "_source" : { "id" : "4", "uta" : "田子の浦に うち出でて見れば 白妙の 富士の高嶺に 雪はふりつつ", "kana" : "たごのうらに うちいでてみれば しろたへの ふじのたかねに ゆきはふりつつ", "kajin" : "山部赤人" } }, { "_index" : "hyaku_index", "_id" : "5gdow5oB41J4chRlTnYZ", "_score" : 3.1701806, "_source" : { "id" : "31", "uta" : "朝ぼらけ ありあけの月と 見るまでに 吉野の里に 降れる白雪", "kana" : "あさぼらけ ありあけのつきと みるまでに よしののさとに ふれるしらゆき", "kajin" : "坂上是則" } }, { "_index" : "hyaku_index", "_id" : "Jwdow5oB41J4chRlUnd0", "_score" : 3.1701806, "_source" : { "id" : "96", "uta" : "花さそふ 嵐の庭の 雪ならで ふりゆくものは わが身なりけり", "kana" : "はなさそふ あらしのにはの ゆきならで ふりゆくものは わがみなりけり", "kajin" : "入道前太政大臣" } }, { "_index" : "hyaku_index", "_id" : "1gdow5oB41J4chRlTXYB", "_score" : 2.7989807, "_source" : { "id" : "15", "uta" : "君がため 春の野に出でて 若菜つむ わが衣手に 雪はふりつつ", "kana" : "きみがため はるののにいでて わかなつむ わがころもでに ゆきはふりつつ", "kajin" : "光孝天皇" } } ] } } elastic-start-local %
データの更新
まず,ドキュメントを一覧で取得し,更新したいドキュメントの _id を確認します.
elastic-start-local % curl -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" --json @json/list_ids_100.json "http://localhost:9200/hyaku_index/_search?pretty" ⏎ { "took" : 1, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 100, "relation" : "eq" }, "max_score" : 1.0, "hits" : [ { "_index" : "hyaku_index", "_id" : "yAdmw5oB41J4chRllnaO", "_score" : 1.0 }, ...(中略)... { "_index" : "hyaku_index", "_id" : "Kwdow5oB41J4chRlUne3", "_score" : 1.0 } ] } } elastic-start-local %
上で取得した最後のドキュメントについてその _id を指定してドキュメントの詳細を取得します.
curl -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" "http://localhost:9200/hyaku_index/_doc/Kwdow5oB41J4chRlUne3?pretty"
実際にコマンドを実行すると次の結果が得られました.
elastic-start-local % curl -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" "http://localhost:9200/hyaku_index/_doc/Kwdow5oB41J4chRlUne3?pretty" ⏎ { "_index" : "hyaku_index", "_id" : "Kwdow5oB41J4chRlUne3", "_version" : 1, "_seq_no" : 99, "_primary_term" : 1, "found" : true, "_source" : { "id" : "100", "uta" : "百敷や ふるき軒端の しのぶにも なほあまりある 昔なりけり", "kana" : "ももしきや ふるきのきばの しのぶにも なほあまりある むかしなりけり", "kajin" : "順徳院" } } elastic-start-local %
上のドキュメントは次のようなコマンドで更新することができます.次のコマンドでは "uta","kajin" という2つのフィールドを更新していますが,"kana" フィールドは更新していないことに注意してください.また,-X POST オプションによって POST メソッドを利用していることにも注意してください.
curl -X POST -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" --json '{
"doc": {
"uta": "今日はメロンパンを食べました",
"kajin": "林坂弘一郎"
}
}' "http://localhost:9200/hyaku_index/_update/Kwdow5oB41J4chRlUne3?pretty"
実際にコマンドを実行します.
elastic-start-local % curl -X POST -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" --json '{
"doc": {
"uta": "今日はメロンパンを食べました",
"kajin": "林坂弘一郎"
}
}' "http://localhost:9200/hyaku_index/_update/Kwdow5oB41J4chRlUne3?pretty" ⏎
{
"_index" : "hyaku_index",
"_id" : "Kwdow5oB41J4chRlUne3",
"_version" : 2,
"result" : "updated",
"_shards" : {
"total" : 1,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 100,
"_primary_term" : 1
}
elastic-start-local %
更新できたことを確認します.このとき,"uta" と "kajin" フィールドが更新されていることに加えて,"kana" フィールドは更新されていないことに注意してください.
elastic-start-local % curl -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" "http://localhost:9200/hyaku_index/_doc/Kwdow5oB41J4chRlUne3?pretty" ⏎ { "_index" : "hyaku_index", "_id" : "Kwdow5oB41J4chRlUne3", "_version" : 2, "_seq_no" : 100, "_primary_term" : 1, "found" : true, "_source" : { "id" : "100", "uta" : "今日はメロンパンを食べました", "kana" : "ももしきや ふるきのきばの しのぶにも なほあまりある むかしなりけり", "kajin" : "林坂弘一郎" } } elastic-start-local %
次に JSON ファイルに更新内容を記載して更新コマンドを実行する方法も確認します.まず次のような JSON ファイルを準備します.
json/update_doc.json
{
"doc": {
"uta": "あいうえお",
"kajin": "かきくけこ"
}
}
これまでと同様に --json オプションを用いて JSON ファイルのパスを指定すれば更新が可能です.
curl -X POST -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" --json @json/update_doc.json "http://localhost:9200/hyaku_index/_update/Kwdow5oB41J4chRlUne3?pretty"
実際にコマンドを実行します.
elastic-start-local % curl -X POST -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" --json @json/update_doc.json "http://localhost:9200/hyaku_index/_update/Kwdow5oB41J4chRlUne3?pretty" ⏎
{
"_index" : "hyaku_index",
"_id" : "Kwdow5oB41J4chRlUne3",
"_version" : 3,
"result" : "updated",
"_shards" : {
"total" : 1,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 101,
"_primary_term" : 1
}
elastic-start-local %
更新できたことを確認します.
elastic-start-local % curl -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" "http://localhost:9200/hyaku_index/_doc/Kwdow5oB41J4chRlUne3?pretty" ⏎ { "_index" : "hyaku_index", "_id" : "Kwdow5oB41J4chRlUne3", "_version" : 3, "_seq_no" : 101, "_primary_term" : 1, "found" : true, "_source" : { "id" : "100", "uta" : "あいうえお", "kana" : "ももしきや ふるきのきばの しのぶにも なほあまりある むかしなりけり", "kajin" : "かきくけこ" } } elastic-start-local %
データの削除
データの削除を行う前に,現在登録されているデータ数(ドキュメント数)が100件であることを確認しておきます.
elastic-start-local % curl -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" "http://localhost:9200/hyaku_index/_count?pretty" ⏎ { "count" : 100, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 } } elastic-start-local %
削除の前に _id を指定して削除したいドキュメントの内容を確認しておきます.
elastic-start-local % curl -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" "http://localhost:9200/hyaku_index/_doc/Kwdow5oB41J4chRlUne3?pretty" ⏎ { "_index" : "hyaku_index", "_id" : "Kwdow5oB41J4chRlUne3", "_version" : 3, "_seq_no" : 101, "_primary_term" : 1, "found" : true, "_source" : { "id" : "100", "uta" : "あいうえお", "kana" : "ももしきや ふるきのきばの しのぶにも なほあまりある むかしなりけり", "kajin" : "かきくけこ" } } elastic-start-local %
ドキュメントの _id を指定して削除するコマンドは次のとおりです.メソッドを -X DELETE で指定していることに注意してください.
curl -X DELETE -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" "http://localhost:9200/hyaku_index/_doc/Kwdow5oB41J4chRlUne3?pretty"
実際にコマンドを実行すると次のような結果が得られました.
elastic-start-local % curl -X DELETE -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" "http://localhost:9200/hyaku_index/_doc/Kwdow5oB41J4chRlUne3?pretty" ⏎ { "_index" : "hyaku_index", "_id" : "Kwdow5oB41J4chRlUne3", "_version" : 4, "result" : "deleted", "_shards" : { "total" : 1, "successful" : 1, "failed" : 0 }, "_seq_no" : 102, "_primary_term" : 1 } elastic-start-local %
削除によってドキュメント数が99件になっているはずなのでそのことを確認します.
elastic-start-local % curl -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" "http://localhost:9200/hyaku_index/_count?pretty" ⏎ { "count" : 99, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 } } elastic-start-local %
次のコマンドではインデックス hyaku_index のすべてのドキュメントを削除できます.
curl -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" --json '{
"query": {
"match_all": {
}
}
}
' "http://localhost:9200/hyaku_index/_delete_by_query?pretty"
実際にコマンドを実行してすべてのドキュメントを削除します.
elastic-start-local % curl -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" --json '{ "query": { "match_all": { } } } ' "http://localhost:9200/hyaku_index/_delete_by_query?pretty" ⏎ { "took" : 44, "timed_out" : false, "total" : 99, "deleted" : 99, "batches" : 1, "version_conflicts" : 0, "noops" : 0, "retries" : { "bulk" : 0, "search" : 0 }, "throttled_millis" : 0, "requests_per_second" : -1.0, "throttled_until_millis" : 0, "failures" : [ ] } elastic-start-local %
件数が0件になっているはずなので,そのことを確認します.
elastic-start-local % curl -H "Authorization: ApiKey ${ES_LOCAL_API_KEY}" "http://localhost:9200/hyaku_index/_count?pretty" ⏎ { "count" : 0, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 } } elastic-start-local %