Elasticsearch お試し
準備
設定を作成
コンテナを起動
docker compose up -d
Kibana コンソールには、 http://localhost:5601 からアクセスできます。
Elasticsearch API を叩いて操作
環境変数を設定しておきます。
ELASTICSEARCH_ENDPOINT=http://localhost:9200
INDEX_NAME=users-test
サーバー
状態の確認
curl -G "${ELASTICSEARCH_ENDPOINT}/_cat/health?v"
curl -G "${ELASTICSEARCH_ENDPOINT}/_cat/nodes?v"
curl -G "${ELASTICSEARCH_ENDPOINT}/_cat/indices?v&s=index"
curl -G "${ELASTICSEARCH_ENDPOINT}/_cat/aliases?v&s=index"
インデックステンプレート
インデックステンプレートの確認
curl -G "${ELASTICSEARCH_ENDPOINT}/_template" | jq
スナップショットリポジトリ
スナップショットリポジトリの確認
curl -G "${ELASTICSEARCH_ENDPOINT}/_snapshot" | jq
スナップショットリポジトリの設定
ファイルシステム指定
REPOSITORY_NAME=backup
LOCATION=/var/elasticsearch/snapshot/backups
curl -X PUT "${ELASTICSEARCH_ENDPOINT}/_snapshot/${REPOSITORY_NAME}" \
    -H "Content-Type: application/json" \
    -d "{
        \"type\": \"fs\",
        \"settings\": {
            \"location\": \"${LOCATION}\"
        }
    }"
Amazon OpenSearch の場合
REPOSITORY_NAME=backup
AWS_REGION=ap-northeast-1
BUCKET_NAME=bucket-name
ROLE_ARN=arn:aws:iam::account-id:role/role-name
curl -X PUT "${ELASTICSEARCH_ENDPOINT}/_snapshot/${REPOSITORY_NAME}" \
    --aws-sigv4 "aws:amz:${AWS_REGION}:es" \
    --user "${AWS_ACCESS_KEY_ID}:${AWS_SECRET_ACCESS_KEY}" \
    -H "X-Amz-Security-Token: ${AWS_SESSION_TOKEN}" \
    -H "Content-Type: application/json" \
    -d "{
        \"type\": \"s3\",
        \"settings\": {
            \"bucket\": \"${BUCKET_NAME}\",
            \"region\": \"${AWS_REGION}\",
            \"role_arn\": \"${ROLE_ARN}\"
        }
    }"
スナップショットリポジトリの削除
REPOSITORY_NAME=backup
curl -X DELETE "${ELASTICSEARCH_ENDPOINT}/_snapshot/${REPOSITORY_NAME}"
Amazon OpenSearch の場合
REPOSITORY_NAME=backup
curl -X DELETE "${ELASTICSEARCH_ENDPOINT}/_snapshot/${REPOSITORY_NAME}" \
    --aws-sigv4 "aws:amz:ap-northeast-1:es" \
    --user "${AWS_ACCESS_KEY_ID}:${AWS_SECRET_ACCESS_KEY}" \
    -H "X-Amz-Security-Token: ${AWS_SESSION_TOKEN}"
スナップショット
スナップショットの確認
REPOSITORY_NAME=backup
curl -G "${ELASTICSEARCH_ENDPOINT}/_snapshot/${REPOSITORY_NAME}/_all" | jq
スナップショット名の一覧だけ
REPOSITORY_NAME=backup
curl -G "${ELASTICSEARCH_ENDPOINT}/_snapshot/${REPOSITORY_NAME}/_all" \
    | jq -r ".snapshots[].snapshot"
スナップショットの取得
REPOSITORY_NAME=backup
SNAPSHOT_NAME=$(date +%Y%m%d%H%M%S)
curl -X PUT "${ELASTICSEARCH_ENDPOINT}/_snapshot/${REPOSITORY_NAME}/${SNAPSHOT_NAME}" | jq
スナップショットの削除
REPOSITORY_NAME=backup
SNAPSHOT_NAME=hoge
curl -X DELETE "${ELASTICSEARCH_ENDPOINT}/_snapshot/${REPOSITORY_NAME}/${SNAPSHOT_NAME}"
スナップショットから復元
REPOSITORY_NAME=backup
SNAPSHOT_NAME=hoge
curl -X POST "${ELASTICSEARCH_ENDPOINT}/_snapshot/${REPOSITORY_NAME}/${SNAPSHOT_NAME}/_restore" \
    -H "Content-Type: application/json" \
    -d "{
        \"indices\": \"${indexName}\"
    }" | jq
復元時に変換する場合の例
REPOSITORY_NAME=backup
SNAPSHOT_NAME=hoge
curl -X POST "${ELASTICSEARCH_ENDPOINT}/_snapshot/${REPOSITORY_NAME}/${SNAPSHOT_NAME}/_restore" \
    -H "Content-Type: application/json" \
    -d "{
        \"indices\": \"${indexName}\",
        \"index_settings\": {
            \"index.analysis.filter.synonym_filter\": {
                \"synonyms\": [],
                \"synonyms_path\": null,
                \"updateable\": null
            }
        }
    }" | jq
インデックス設定
インデックス設定を取得
curl -G "${ELASTICSEARCH_ENDPOINT}/${INDEX_NAME}" | jq
インデックスの Mappings 設定を取得
curl -G "${ELASTICSEARCH_ENDPOINT}/${INDEX_NAME}/_mapping" | jq
インデックス設定・更新
curl -X PUT "${ELASTICSEARCH_ENDPOINT}/${INDEX_NAME}" \
    -H "Content-Type: application/json" \
    -d @index.json
インデックスの削除
curl -X DELETE "${ELASTICSEARCH_ENDPOINT}/${INDEX_NAME}"
エイリアス
エイリアスの設定
INDEX_NAME=test-v2
INDEX_ALIAS=test
curl -X POST "${ELASTICSEARCH_ENDPOINT}/_aliases" \
    -H "Content-Type: application/json" \
    -d "{
        \"actions\": [
            {
                \"add\": {
                    \"index\": \"${INDEX_NAME}\",
                    \"alias\": \"${INDEX_ALIAS}\"
                }
            }
        ]
    }"
エイリアスの削除
INDEX_NAME=test-v2
INDEX_ALIAS=test
curl -X POST "${ELASTICSEARCH_ENDPOINT}/_aliases" \
    -H "Content-Type: application/json" \
    -d "{
        \"actions\": [
            {
                \"remove\": {
                    \"index\": \"${INDEX_NAME}\",
                    \"alias\": \"${INDEX_ALIAS}\"
                }
            }
        ]
    }"
参照
ドキュメントの取得
DOC_ID=doc-1
curl -G "${ELASTICSEARCH_ENDPOINT}/${INDEX_NAME}/_doc/${DOC_ID}"
アナライザー
ANALYZER_NAME=search_analyzer_ja
SEARCH_TEXT=リクルートホールディングス
curl -s -X GET "${ELASTICSEARCH_ENDPOINT}/companies/_analyze" -H "Content-Type: application/json" \
    -d "{\"analyzer\": \"${ANALYZER_NAME}\", \"text\": \"${SEARCH_TEXT}\"}" | jq
検索
検索 (全て)
curl -X GET "${ELASTICSEARCH_ENDPOINT}/${INDEX_NAME}/_search" \
    -H "Content-Type: application/json" \
    -d "{
        \"query\": {
            \"match_all\": {}
        },
        \"from\": 0,
        \"size\": 10,
        \"sort\": [{\"_id\": \"asc\"}]
    }" | jq
検索 (取得フィールド指定)
curl -X GET "${ELASTICSEARCH_ENDPOINT}/${INDEX_NAME}/_search" \
    -H "Content-Type: application/json" \
    -d "{
        \"_source\": [\"title\"],
        \"query\": {
            \"match_all\": {}
        },
        \"from\": 0,
        \"size\": 1000,
        \"sort\": [{\"_id\": \"asc\"}]
    }" | jq
検索 (件数取得)
curl -X GET "${ELASTICSEARCH_ENDPOINT}/${INDEX_NAME}/_count" \
    -H "Content-Type: application/json" \
    -d "{
        \"query\": {
            \"match_all\": {}
        }
    }" | jq
検索 (完全一致)
curl -X GET "${ELASTICSEARCH_ENDPOINT}/${INDEX_NAME}/_search" \
    -H "Content-Type: application/json" \
    -d "{
        \"query\": {
            \"term\": {
                \"tags\": \"女性\"
            }
        },
        \"from\": 0,
        \"size\": 10,
        \"sort\": [{\"_id\": \"asc\"}]
    }" | jq
フィールドに "type": "keyword" を指定していない場合は .keyword をつける。
curl -X GET "${ELASTICSEARCH_ENDPOINT}/${INDEX_NAME}/_search" \
    -H "Content-Type: application/json" \
    -d "{
        \"query\": {
            \"term\": {
                \"tags.keyword\": \"女性\"
            }
        },
        \"from\": 0,
        \"size\": 10,
        \"sort\": [{\"_id\": \"asc\"}]
    }" | jq
検索 (ワイルドカード)
curl -X GET "${ELASTICSEARCH_ENDPOINT}/${INDEX_NAME}/_search" \
    -H "Content-Type: application/json" \
    -d "{
        \"query\": {
            \"wildcard\": {
                \"post.extras.company.keyword\": \"21/*\"
            }
        }
    }" | jq
検索 (Nested)
Nested Field に対して複合検索
curl -X GET "${ELASTICSEARCH_ENDPOINT}/${INDEX_NAME}/_search" \
    -H "Content-Type: application/json" \
    -d "{
        \"query\": {
            \"nested\": {
                \"path\": \"categories\",
                \"query\": {
                    \"bool\": {
                        \"must\": [
                            {
                                \"term\": {
                                    \"categories.category\": \"catg2\"
                                }
                            },
                            {
                                \"term\": {
                                    \"categories.subCategory\": \"subcatg1\"
                                }
                            }
                        ]
                    }
                }
            }
        }
    }" | jq
検索 (いずれか完全一致)
複数の OR 検索は terms を使う。
curl -X GET "${ELASTICSEARCH_ENDPOINT}/${INDEX_NAME}/_search" \
    -H "Content-Type: application/json" \
    -d "{
        \"query\": {
            \"terms\": {
                \"tags\": [\"女性\", \"インターン\"]
            }
        },
        \"from\": 0,
        \"size\": 10,
        \"sort\": [{\"_id\": \"asc\"}]
    }" | jq
検索 (NOT)
curl -X GET "${ELASTICSEARCH_ENDPOINT}/${INDEX_NAME}/_search" \
    -H "Content-Type: application/json" \
    -d "{
        \"query\": {
            \"bool\": {
                \"must_not\": [
                    {
                        \"term\": {
                            \"tags\": \"女性\"
                        }
                    }
                ]
            }
        },
        \"from\": 0,
        \"size\": 10,
        \"sort\": [{\"_id\": \"asc\"}]
    }" | jq
検索 (match)
curl -X GET "${ELASTICSEARCH_ENDPOINT}/${INDEX_NAME}/_search" \
    -H "Content-Type: application/json" \
    -d "{
        \"query\": {
            \"match\": {
                \"title\": \"起業\"
            }
        },
        \"from\": 0,
        \"size\": 10,
        \"sort\": [{\"_score\": \"desc\"}]
    }" | jq
検索 (match_phrase)
curl -X GET "${ELASTICSEARCH_ENDPOINT}/${INDEX_NAME}/_search" \
    -H "Content-Type: application/json" \
    -d "{
        \"query\": {
            \"match_phrase\": {
                \"title\": \"起業\"
            }
        },
        \"from\": 0,
        \"size\": 10,
        \"sort\": [{\"_score\": \"desc\"}]
    }" | jq
検索 (AND)
curl -X GET "${ELASTICSEARCH_ENDPOINT}/${INDEX_NAME}/_search" \
    -H "Content-Type: application/json" \
    -d "{
        \"query\": {
            \"bool\": {
                \"must\": [
                    {
                        \"match\": {
                            \"title\": \"起業\"
                        }
                    },
                    {
                        \"match\": {
                            \"title\": \"女性\"
                        }
                    }
                ]
            }
        },
        \"from\": 0,
        \"size\": 10,
        \"sort\": [{\"_score\": \"desc\"}]
    }" | jq
- OR の場合は mustの代わりにshouldを指定する
検索 (現在日時と比較)
curl -X GET "${ELASTICSEARCH_ENDPOINT}/${INDEX_NAME}/_search" \
    -H "Content-Type: application/json" \
    -d "{
        \"query\": {
            \"range\": {
                \"publishDatetime\": {
                    \"lt\": \"now\",
                    \"time_zone\": \"+09:00\"
                }
            }
        }
    }" | jq
検索 (集計)
curl -X GET "${ELASTICSEARCH_ENDPOINT}/${INDEX_NAME}/_search" \
    -H "Content-Type: application/json" \
    -d "{
        \"aggs\": {
            \"group_by_category\": {
                \"terms\": {
                    \"field\": \"category\"
                }
            }
        },
        \"size\": 0
    }" | jq
ドキュメントの作成・更新
DOC_ID=doc-1
curl -X PUT "${ELASTICSEARCH_ENDPOINT}/${INDEX_NAME}/_doc/${DOC_ID}" \
    -H "Content-Type: application/json" \
    -d "{
        \"name\": \"鈴木 太郎\"
    }"
ドキュメントの部分更新
DOC_ID=doc-1
curl -X POST "${ELASTICSEARCH_ENDPOINT}/${INDEX_NAME}/_update/${DOC_ID}" \
    -H "Content-Type: application/json" \
    -d "{
        \"doc\": {
            \"name\": \"鈴木 太郎 $(date +%Y%m%d%H%M%S)\"
        }
    }"
ドキュメントのバルク登録
curl -X POST "${ELASTICSEARCH_ENDPOINT}/_bulk" \
    -H "Content-Type: application/json" \
    -d "
        {\"index\": {\"_index\": \"${INDEX_NAME}\", \"_id\": \"${DOC_ID}\"}}
        {\"name\": \"鈴木 太郎\"}
    "
ドキュメントの削除
DOC_ID=doc-1
curl -X DELETE "${ELASTICSEARCH_ENDPOINT}/${INDEX_NAME}/_doc/${DOC_ID}"
全ドキュメントの削除
curl -X POST "${ELASTICSEARCH_ENDPOINT}/${INDEX_NAME}/_delete_by_query" \
    -d '{"query": {"match_all": {}}}'