Elastic App Searchを入れた環境のElasticsearchをKibanaで覗く

概要

Elastic App Search(オンプレミス版)を入れたら、接続されているElasticsearchにどんなインデックスが作成されるのか、マッピングはどうなのYO!? Kibanaで覗いてみた結果を貼ってみます。

前回までは

前回はElastic App SearchをDockerで動かす、というのをやりました。

tsgkdt.hatenablog.jp

ここで作成した環境を使って、Kibanaで覗いてどんなインデックスが作成されてるのか、マッピングがどうなっているのか?を確認していきます。

インデックスの確認

KibanaのDevToolsでインデックス一覧を確認してみましょう。

GET _cat/indices?v&s=index

としますと、こんな結果が返りました。

health status index                                                                               uuid                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open   .app-search-actastic-clusters                                                       MfM1vdoUQOmXlEyZrssgDA   1   1          1            0      5.7kb          5.7kb
yellow open   .app-search-actastic-clusters-name-unique-constraint                                bUvAnwtfTJSPANOkLhuceA   1   1          1            0      3.1kb          3.1kb
yellow open   .app-search-actastic-document_types                                                 7TTmZWh-RrCEHihbO5XoaA   1   1          1            0      5.6kb          5.6kb
yellow open   .app-search-actastic-document_types-engine_id-slug-unique-constraint                MxLayZiOQeuDLsFKAhCTDA   1   1          1            0      3.1kb          3.1kb
yellow open   .app-search-actastic-elasticsearch_indices                                          taeplLguR1-Z0fFp4FV_hA   1   1          1            0      5.6kb          5.6kb
yellow open   .app-search-actastic-engine_document_backends                                       6tSqK5LWS3yZBsdHxXuJRg   1   1          1            0      5.9kb          5.9kb
yellow open   .app-search-actastic-engines                                                        1AMN92uHSIuFQ-fdwsBF8w   1   1          1            0     11.3kb         11.3kb
yellow open   .app-search-actastic-engines-account_id-loco_moco_account_id-slug-unique-constraint sVynZmHSS2Cqb7sWs5_Lgw   1   1          1            0      3.2kb          3.2kb
yellow open   .app-search-actastic-engines-key-unique-constraint                                  IKmt6hg-TRi3gPFi-b278g   1   1          1            0      3.1kb          3.1kb
yellow open   .app-search-actastic-index_pointers                                                 Uvi6k8njTYCARVzvq8OrsQ   1   1          1            0      6.5kb          6.5kb
yellow open   .app-search-actastic-loco_moco_accounts                                             6PrGFgdDQBSXyAyJ6UeIOA   1   1          1            0      5.5kb          5.5kb
yellow open   .app-search-actastic-loco_moco_accounts-key-unique-constraint                       k9hKYRtUT_C_XfrReFTu_A   1   1          1            0      3.1kb          3.1kb
yellow open   .app-search-actastic-loco_moco_api_token_engines                                    ahOdNulqQ4iTnWI4ZVPKQQ   1   1          0            0       261b           261b
yellow open   .app-search-actastic-loco_moco_api_tokens                                           VfGE9oSxSmagk7siSlQICg   1   1          2            0       13kb           13kb
yellow open   .app-search-actastic-loco_moco_api_tokens-authentication_token-unique-constraint    0mgrgouyR-6NxmnH1ce1fA   1   1          2            0      6.5kb          6.5kb
yellow open   .app-search-actastic-loco_moco_document_position_queries                            Ay9c593DTj6kFqEweiC89g   1   1          0            0       261b           261b
yellow open   .app-search-actastic-loco_moco_document_positions                                   ACSW98cuR6aPps1KJ7ORyw   1   1          0            0       261b           261b
yellow open   .app-search-actastic-loco_moco_invitations                                          1cT1cdvpQsCgPmXT61ey8Q   1   1          0            0       261b           261b
yellow open   .app-search-actastic-loco_moco_roles                                                zuheAIWIQFWCBCmXNzC0Bg   1   1          1            0      5.3kb          5.3kb
yellow open   .app-search-actastic-loco_moco_search_settings                                      v5JzaCe6TUWfITL1WOF3uQ   1   1          0            0       261b           261b
yellow open   .app-search-actastic-reindex_jobs                                                   0ToDVV9yStah0yjhl4et3A   1   1          0            0       261b           261b
yellow open   .app-search-actastic-synonyms                                                       ratUO5kaQ9S28gHG9-BKoA   1   1          0            0       261b           261b
yellow open   .app-search-actastic-users                                                          QDSo5ahNQGmwEYmaBiQOSg   1   1          1            0      9.7kb          9.7kb
yellow open   .app-search-actastic-users-email-unique-constraint                                  Nw_eZ8LIS0yHXTD4dlN00g   1   1          1            0      3.1kb          3.1kb
green  open   .app-search-analytics-logs-loco_togo_production-6.4.2-2019.01.04                    60LlyHNLQLWyf5Vbv9tSog   1   0          4            0     55.6kb         55.6kb
green  open   .app-search-analytics-logs-loco_togo_production-6.4.2-2019.01.06                    oMgZ7QQPQKqoldBn4AhLFQ   1   0          7            0       94kb           94kb
green  open   .app-search-app-logs-loco_togo_production-6.4.2-2019.01.04                          jzumVhK7SH6hvto32KN35w   1   0        127            0      1.7mb          1.7mb
green  open   .app-search-app-logs-loco_togo_production-6.4.2-2019.01.06                          WZsyjrn8QFCXECnx0GUxnA   1   0         91            0      757kb          757kb
yellow open   .app-search-db-lock                                                                 7T_7cxiMRj-Kljfn3vJvaw   1   1          0            0       261b           261b
yellow open   .app-search-document-backend-5c2f7a47b34f5f799a8e7691                               0ltdjqx2SJaxW_ufXoD6Vg   1   1          2            0     11.6kb         11.6kb
green  open   .app-search-engine-5c2f7a47b34f5f799a8e7691                                         fotpWaWmQ9udK9v8VCAZ9A   1   0          2            0     24.8kb         24.8kb
yellow open   .app-search-esqueues-me_queue_v1_account_destroyer                                  Tooi_zvlTMCUWBQSKLjdeA   1   1          0            0       261b           261b
yellow open   .app-search-esqueues-me_queue_v1_analytics_events                                   QUVshquSRdir3ZkUDAkR8g   1   1          0            0       261b           261b
yellow open   .app-search-esqueues-me_queue_v1_document_destroyer                                 O2UKg7K6SO2_c_O3AxIXTQ   1   1          0            0       261b           261b
yellow open   .app-search-esqueues-me_queue_v1_engine_destroyer                                   WleKaeY8Qz-movtrVv-jfA   1   1          0            0       261b           261b
yellow open   .app-search-esqueues-me_queue_v1_index_adder                                        GeTP4LIFRHOM_wgVMNoM3w   1   1          0            0       259b           259b
yellow open   .app-search-esqueues-me_queue_v1_indexed_doc_remover                                gaxVxz7kSoaPFY7JVIOcDw   1   1          0            0       261b           261b
yellow open   .app-search-esqueues-me_queue_v1_refresh_document_counts                            JvkmsO7kT2-D1JhIoLcWPg   1   1          0            0       259b           259b
yellow open   .app-search-esqueues-me_queue_v1_reindexer                                          Jc2By9V5SAieI-2F1RHaMQ   1   1          0            0       261b           261b
green  open   .kibana_1                                                                           jBWGxL9BSMKbDHXUM1D50g   1   0          3            0     11.9kb         11.9kb

ざっと眺めて

App Searchとして管理すべき情報を、ほとんどElasticsearchに入れて管理しようとしている、ということが感じられます。 よく、「Elasticsearchは全文検索のシステムであって、RDBMSじゃないんだから」などと言われることもありますが、 db_lockとかRDBMSを想起させるような名前がついたインデックスがあるのは、用途は分かりませんが面白いですね。

シャード、レプリカの設定

シャード(pri)、レプリカ(rep)の数が、ほとんどのインデックスで1/1となっています。 ログはレプリカが0になっています。

このあたりは格納されるドキュメントの数が増えると変わるのかもしれませんが、初期値としてはこのようになっているようです。

ユーザ設定

ユーザの設定については、.app-search-actastic-usersに格納されています。

POST _xpack/sql?format=csv
{
  "query": "describe \".app-search-actastic-users\""
}

とやって、列定義を見てみましょう。

column,type,mapping
cloudflare_account_id,VARCHAR,KEYWORD
confirmation_auto_sign_in_token,VARCHAR,KEYWORD
confirmation_auto_sign_in_token_created_at,TIMESTAMP,DATE
confirmation_sent_at,TIMESTAMP,DATE
confirmation_token,VARCHAR,KEYWORD
confirmed_at,TIMESTAMP,DATE
created_at,TIMESTAMP,DATE
current_sign_in_at,TIMESTAMP,DATE
current_sign_in_ip,VARCHAR,KEYWORD
email,VARCHAR,KEYWORD
email_status,VARCHAR,KEYWORD
encrypted_password,VARCHAR,KEYWORD
failed_attempts,BIGINT,LONG
fv_landing,VARCHAR,KEYWORD
fv_landing_ca,VARCHAR,KEYWORD
fv_refdom,VARCHAR,KEYWORD
fv_time,BIGINT,LONG
heroku_id,VARCHAR,KEYWORD
id,VARCHAR,KEYWORD
last_sign_in_at,TIMESTAMP,DATE
last_sign_in_ip,VARCHAR,KEYWORD
locked_at,TIMESTAMP,DATE
name,VARCHAR,KEYWORD
picture_url,VARCHAR,KEYWORD
receive_analytics_email,BOOLEAN,BOOLEAN
remember_created_at,TIMESTAMP,DATE
reset_password_sent_at,TIMESTAMP,DATE
reset_password_token,VARCHAR,KEYWORD
shopify_access_token,VARCHAR,KEYWORD
shopify_shop,VARCHAR,KEYWORD
sign_in_count,BIGINT,LONG
unconfirmed_email,VARCHAR,KEYWORD
unlock_token,VARCHAR,KEYWORD
updated_at,TIMESTAMP,DATE
wordpress_signup,BOOLEAN,BOOLEAN

暗号化されたパスワードを格納するカラムが用意されていることが分かります。 App Searchとしてどう使えるのかは不明ですが、wordpress_signupやheroku_idといったカラムがあるのは、そういったシステムとの連携が出来るのかな? と予感させます。

ドキュメント

前回作成したテストドキュメントは、.app-search-engine-5c2f7a47b34f5f799a8e7691に入っていました。

match_allで中身を確認してみますと、確かに2件、テストドキュメントとして登録したものが格納されていることが確認できました。

f:id:tsgkdt:20190107003520p:plain
DevTools query match-all

__st_text_summary__st_expires_afterは、テストドキュメントを登録したときのjsonにはなかった項目ですね。 このあたりはApp Search側で付与して管理される項目のようです。

インデックス設定の確認

どんなanalyzerやtokenizerの設定がなされるのか、が気になるところです。 App SearchでEngineを追加するときに、日本語を指定したため、日本語検索用の設定が見られるのでは、と期待してこれを確認していきます。

GET .app-search-engine-5c2f7a47b34f5f799a8e7691/_settings

とやって、返ってきたjsonの中からanalysisの部分を抜き出したものが以下です。

        "analysis" : {
          "filter" : {
            "front_ngram" : {
              "type" : "edge_ngram",
              "min_gram" : "1",
              "max_gram" : "12"
            },
            "bigram_joiner" : {
              "max_shingle_size" : "2",
              "token_separator" : "",
              "output_unigrams" : "false",
              "type" : "shingle"
            },
            "bigram_max_size" : {
              "type" : "length",
              "max" : "16",
              "min" : "0"
            },
            "phrase_shingle" : {
              "max_shingle_size" : "3",
              "min_shingle_size" : "2",
              "output_unigrams" : "true",
              "type" : "shingle"
            },
            "delimiter" : {
              "split_on_numerics" : "true",
              "generate_word_parts" : "true",
              "preserve_original" : "false",
              "catenate_words" : "true",
              "generate_number_parts" : "true",
              "catenate_all" : "true",
              "split_on_case_change" : "true",
              "type" : "word_delimiter_graph",
              "catenate_numbers" : "true",
              "stem_english_possessive" : "true"
            },
            "ja-stop-words-filter" : {
              "type" : "stop",
              "stopwords" : "_english_"
            },
            "ja-stem-filter" : {
              "name" : "light_english",
              "type" : "stemmer"
            }
          },
          "analyzer" : {
            "i_prefix" : {
              "filter" : [
                "cjk_width",
                "lowercase",
                "asciifolding",
                "front_ngram"
              ],
              "tokenizer" : "standard"
            },
            "iq_intragram" : {
              "filter" : [
                "cjk_width",
                "lowercase",
                "asciifolding"
              ],
              "tokenizer" : "intragram_tokenizer"
            },
            "iq_phrase_shingle" : {
              "filter" : [
                "cjk_width",
                "lowercase",
                "asciifolding",
                "phrase_shingle"
              ],
              "tokenizer" : "standard"
            },
            "iq_text_delimiter" : {
              "filter" : [
                "delimiter",
                "cjk_width",
                "lowercase",
                "asciifolding",
                "ja-stop-words-filter",
                "ja-stem-filter",
                "cjk_bigram"
              ],
              "tokenizer" : "whitespace"
            },
            "q_prefix" : {
              "filter" : [
                "cjk_width",
                "lowercase",
                "asciifolding"
              ],
              "tokenizer" : "standard"
            },
            "iq_text_base" : {
              "filter" : [
                "cjk_width",
                "lowercase",
                "asciifolding",
                "ja-stop-words-filter"
              ],
              "tokenizer" : "standard"
            },
            "iq_text_stem" : {
              "filter" : [
                "cjk_width",
                "lowercase",
                "asciifolding",
                "ja-stop-words-filter",
                "ja-stem-filter",
                "cjk_bigram"
              ],
              "tokenizer" : "standard"
            },
            "iq_text_bigram" : {
              "filter" : [
                "cjk_width",
                "lowercase",
                "asciifolding",
                "ja-stem-filter",
                "bigram_joiner",
                "bigram_max_size"
              ],
              "tokenizer" : "standard"
            }
          },
          "tokenizer" : {
            "intragram_tokenizer" : {
              "token_chars" : [
                "letter",
                "digit"
              ],
              "min_gram" : "3",
              "type" : "ngram",
              "max_gram" : "4"
            }
          }
        }

ja_*という設定があるところを見ると、日本語用の設定がされていると見ることができそうです。

kuromojiやgosen、sudachiといったアプローチがなかったのは、ちょっと予想外だったところですが、cjk_bigramをうまく使ってるようです。 prefix検索用にedge_ngramを使っているところからみても、基本的にはngramでのアプローチなのかな、と見えました。

intragram_tokenizerというTokenizerの指定にも工夫がありそうですね。

マッピングの確認

複数のanalyzerが用意されていることが分かったので、フィールドとの関係を見ていきます。

f:id:tsgkdt:20190107005228p:plain
mapping

bodyフィールドの定義を見てみますと、こんな感じになっていました。

"body$string" : {
            "type" : "text",
            "index_options" : "offsets",
            "fields" : {
              "delimiter" : {
                "type" : "text",
                "term_vector" : "with_positions_offsets",
                "index_options" : "offsets",
                "analyzer" : "iq_text_delimiter",
                "position_increment_gap" : 100
              },
              "enum" : {
                "type" : "keyword",
                "ignore_above" : 2048
              },
              "intragram" : {
                "type" : "text",
                "index_options" : "docs",
                "analyzer" : "iq_intragram"
              },
              "joined" : {
                "type" : "text",
                "term_vector" : "with_positions_offsets",
                "index_options" : "offsets",
                "analyzer" : "iq_text_bigram",
                "position_increment_gap" : 100
              },
              "prefix" : {
                "type" : "text",
                "term_vector" : "with_positions_offsets",
                "index_options" : "docs",
                "analyzer" : "i_prefix",
                "search_analyzer" : "q_prefix"
              },
              "stem" : {
                "type" : "text",
                "term_vector" : "with_positions_offsets",
                "index_options" : "offsets",
                "analyzer" : "iq_text_stem",
                "position_increment_gap" : 100
              }
            },
            "analyzer" : "iq_text_base",
            "position_increment_gap" : 100
          }

1つのフィールドも、複数のフィールドに分けて、それぞれAnalyzerを設定していることが見て取れますね。

prefixとついたフィールドの設定を見ると、インデックス時のAnalyzerと検索時のAnalyzerが、i_prefixq_prefixで違うものになっていることに気づきます。 この名前からすると、iq_* となっていたのは、インデックス時も検索時も共通して使うもの、と理解できそうです。

終わりに

細かな設定値を1つずつ検証することはしていませんが、アプローチが感じられただけでも収穫でした。 単純な2-gramでやっているのではなく、連結したり、Prefix用にEdge-Ngramを使っていたりするところが参考になりました。

Analysisの設定やマッピングの設定は分かった、じゃあ、検索時にはどういうクエリを投げているのか?(複数フィールドを指定しているだろうし) シノニムとかは、いつ展開しているの? とか。 次は、こういうことが気になってきますね。おいおい調べてみたいところです。

ではまた。