blog

Elasticsearchは最初からあきらめる:ブラインドマッピング

以前は、インデックス、検索、単語のスプリッタについて話し、今日は別の基本的なコンテンツについて話をする - マッピング。 スキーマ内のリレーショナルデータベースに相当するステータスのマッピングは、イン...

Dec 23, 2020 · 9 min. read
シェア

以前、Elasticsearchのインデックス作成、検索、ソーターについてお話しましたが、今日はもう一つの基本であるマッピングについてお話します。

Elasticsearch における Mapping はリレーショナルデータベースにおけるスキーマに相当し、インデックスにおけるフィールド名の定義、フィールドのデータ型の定義、フィールドの設定に利用できます。Elasticsearch 7.0 以降では、型情報を定義する必要はありません

フィールドのデータ型

Mappingでフィールドのデータ型を定義できると書きましたが、これはおそらくMappingで最もよく使われる機能だと思います。

  • 単純な型:テキスト、キーワード、日付、long、double、boolean、ip
  • 複雑な型:オブジェクト型、入れ子型
  • 特殊な型: geo_point, geo_shape 地理的な位置を記述するためのものです。

Elasticsearch がサポートしているデータ型はこれらよりも遥かに多く、スペースの都合上ここでは全てを列挙しません。私の仕事の中でよくあるものをいくつか探して紹介します。

まず文字列ですが、Elasticsearchではテキスト型とキーワード型の2種類があります。テキスト型の文字列は全文検索が可能で、レキサによって使用されます。

PUT my_index
{
 "mappings": {
 "properties": {
 "full_name": {
 "type": "text"
 }
 }
 }
}

フィールドタイプをテキストに設定するとき、フィールドをさらにカスタマイズするために使用できるパラメーターがいくつかあります。

index: このフィールドを検索できるかどうかのフラグ。

search_analyzer: 検索に使用するアナライザ。デフォルトは設定で設定したもの。

fielddata: フィールドでソートやメモリ内での集計が可能かどうか。

meta: フィールドに関するメタデータ。

いくつかのID、メールボックス、ドメイン名などのフィールドのように、キーワード型を使用する必要があります。キーワード型はソートや集約をサポートし、正確なクエリのみをサポートすることができるからです。

IDを数値型に設定する生徒もいるかもしれませんが、それは問題ありません。数値型とキーワードにはそれぞれの利点があり、数値型の使用は範囲内で見つけることができ、キーワード型の使用は照会効率が高くなります。具体的な使い分けは、シーンの用途にもよります。

Elasticsearchでは、日付の型は3つの方法で表現されます。

  1. 2020-07-26 "や "2015/01/01 12:10:30 "のように、日付型の文字列としてフォーマットできます。
  2. ミリ秒のタイムスタンプはlong型で表されます。
  3. 2番目のタイムスタンプは整数型で表現されます。

Elasticsearch の内部では、日付の型は long 型のミリ秒タイムスタンプとして保存され、タイムゾーンはタイムゾーン 0 を使用します。

時間フォーマットはカスタマイズ可能です。"2015/01/01 12:10:30"

strict_date_optional_time||epoch_millisstrict_date_optional_time_nanosは、少なくとも年を含むように解析された一般的な日付書式で、時刻を含む場合はTで区切られます(例:yyyy-MM-dd)。

複数の日付書式を同時にサポートしたい場合は、書式フィールド

PUT my_index
{
 "mappings": {
 "properties": {
 "date": {
 "type": "date",
 "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
 }
 }
 }
}

Mapping

Mappingの日付フォーマットを設定するformatパラメータについて述べましたが、Mappingには他にも多くのパラメータが用意されています。

  • analyzer
  • boost
  • coerce
  • copy_to
  • doc_values
  • dynamic
  • eager_global_ordinals
  • enabled
  • fielddata
  • fields
  • format
  • ignore_above
  • ignore_malformed
  • index_options
  • index_phrases
  • index_prefixes
  • index
  • meta
  • normalizer
  • norms
  • null_value
  • position_increment_gap
  • properties
  • search_analyzer
  • similarity
  • store
  • term_vector

で、よく使われるフィールドをいくつか紹介します。

fields

1つ目はFIELDSで、同じフィールドを目的に応じて使い分けることができます。

例えば、文字列フィールドは全文検索のためにテキスト・タイプに設定することができ、フィールドはソートや集計のためにキーワード・タイプに設定することができます。

PUT my-index-000001
{
 "mappings": {
 "properties": {
 "city": {
 "type": "text",
 "fields": {
 "raw": {
 "type": "keyword"
 }
 }
 }
 }
 }
}

クエリは、全文検索にはcityを、ソートや集計にはcity.rawを使用することができます。

GET my-index-000001/_search
{
 "query": {
 "match": {
 "city": "york" 
 }
 },
 "sort": {
 "city.raw": "asc" 
 },
 "aggs": {
 "Cities": {
 "terms": {
 "field": "city.raw" 
 }
 }
 }
}

enabled

フィールドをデータストアとしてのみ使用し、検索に使用する必要がない場合があります。 この場合、フィールドを無効にすることができます。フィールドが無効になると、フィールドが保持する値はマッピングで指定された型によって制御されなくなります。

PUT my-index-000001
{
 "mappings": {
 "properties": {
 "user_id": {
 "type": "keyword"
 },
 "last_updated": {
 "type": "date"
 },
 "session_data": { 
 "type": "object",
 "enabled": false
 }
 }
 }
}

上記の例では、session_dataフィールドが無効になっているので、session_dataフィールドにJSONと非JSONの両方のデータを格納することができます。

個々のフィールドを無効にするだけでなく、マッピング全体を無効にしてインデックスを再作成することも可能です。

PUT my-index-000002
{
 "mappings": {
 "enabled": false 
 }
}

この時点では、ドキュメントのすべてのフィールドはインデックス化されておらず、保存のために使用されているだけです。

重要なことは、enabled 属性を特定のフィールドやマッピング全体で変更してはいけないということです。いったん false に設定すると、Elasticsearch はそのフィールドにインデックスを作成せず、データの正当性を検証しません。

null_value

null は Elasticsearch ではインデックス化も検索もできません。null というのは、ある言語の狭い意味での null ではなく、すべての null 値を意味します。例えば、すべての値は null 配列です。 要するに、ここでは値がないという定義です。

Elasticsearch は null_value パラメータを提供しており、検索時に null 値の代わりに使用する値を指定することができます。

栗をくれ

PUT my-index-000001
{
 "mappings": {
 "properties": {
 "status_code": {
 "type": "keyword",
 "null_value": "NULL" 
 }
 }
 }
}

status_codeフィールドのnull_valueに "NULL "を設定します。この例でstatus_codeの型がlongの場合、null_valueに "NULL "を設定することはできません。

dynamic

新しく追加されたフィールド

  • dynamicをtrueに設定すると、新しいフィールドを持つドキュメントが書き込まれるとすぐにMappingが更新されます。
  • dynamicをfalseに設定すると、マッピングは更新されず、新しいフィールドはインデックスされません。
  • dynamicがstrictに設定されている場合、ドキュメントの書き込みに失敗します。

既存のフィールドについては、一度データが書き込まれると、フィールド定義の変更はサポートされません。

Dynamic Mapping

インデックスを作成する際に手作業でマッピングを記述する代わりに、Elasticsearch はフィールドの型を自動的に識別する手助けをします。これを動的マッピングと呼びますが、導出があまり正確でないこともあります。

Elasticsearch の自動型認識は JSON に基づいています。データ型の対応は以下の通りです。

nullNo field is added.
真偽boolean field
floating point numberboolean field
整数float
integerlong field
objectobject field
arrayDepends on the first non-null value in the array.

Elasticsearch がフィールドマッピングでサポートするデータ型はこのdate記載されており、それ以外のデータ型マッピングはこの通りに指定する必要があります。

yyyy/MM/dd HH:mm:ss||yyyy/MM/dd||epoch_millis日付型に関しては、デフォルトでマッピング可能ですが、Elasticsearchはいくつかのフォーマットでしか日付を認識できません。date_detectionスイッチをオフにすると、日付は文字列としてのみ認識されます。

PUT my-index-000001
{
 "mappings": {
 "date_detection": false
 }
}

dynamic_date_formats もちろん、必要に応じて自分で認識する日付書式を指定することもできます。

PUT my-index-000001
{
 "mappings": {
 "dynamic_date_formats": ["MM/dd/yyyy"]
 }
}

これは numeric_detection スイッチで制御します。

PUT my-index-000005
{
 "mappings": {
 "numeric_detection": true
 }
}
PUT my-index-000005/_doc/1
{
 "my_float": "1.0", 
 "my_integer": "1" 
}

この例では、my_floatはfloatとして、my_integerはlongとして認識されます。

Dynamic template

 "dynamic_templates": [
 {
 "my_template_name": { 
 ... match conditions ... 
 "mapping": { ... } 
 }
 },
 ...
 ]

my_template_name には任意の文字列を指定できます。

マッチ条件には match_mapping_type、 match、 match_pattern、 unmatch、 path_match、 path_unmatch があります。

マッピングは、マッチするフィールドに使われるべきマッピングです。

match_mapping_type

簡単な例から始めましょう。

PUT my-index-000001
{
 "mappings": {
 "dynamic_templates": [
 {
 "integers": {
 "match_mapping_type": "long",
 "mapping": {
 "type": "integer"
 }
 }
 },
 {
 "strings": {
 "match_mapping_type": "string",
 "mapping": {
 "type": "text",
 "fields": {
 "raw": {
 "type": "keyword",
 "ignore_above": 256
 }
 }
 }
 }
 }
 ]
 }
}

1つはlong型の代わりにinteger型を使用するもので、もう1つは文字列型をキーワードにマッピングするものです。

match とアンマッチ

matchはパターンにマッチするフィールド、unmatchはマッチしないフィールドです。

PUT my-index-000001
{
 "mappings": {
 "dynamic_templates": [
 {
 "longs_as_strings": {
 "match_mapping_type": "string",
 "match": "long_*",
 "unmatch": "*_text",
 "mapping": {
 "type": "long"
 }
 }
 }
 ]
 }
}

この例では、_textで終わる文字列フィールドではなく、long_で始まる文字列が必要です。

上記の3つの他に、正規マッチングを行うmatch_pattern、フィールドがあるパスにマッチするpath_matchとpath_unmatchがあります。

さらに、ダイナミック・テンプレートは{name}と{dynamic_type}の2種類の変数置換をサポートしています。nameはフィールドの名前で、dynamic_typeは検出されたフィールドの型です。

まとめ

Elasticsearchのマッピングについては、最初のチャットで、マッピングの設定は経験が必要だと思います、より多くのケースを扱うとき、あなたはより簡単にマッピングをより良く設定する方法を知ることができるようになります。また、マッピングのフィールドやパラメータの多くは、テキストではカバーされていません、私にとっては、それらのほとんどは、ドキュメントを調べるために使用されますが、ドキュメントを見てみることもお勧めします、少なくとも問題が発生したときに、ドキュメントを調べる方向を知ることができます。そうすることで、周りの人よりもずっと良くなります。

Read next

python plotting 03|matplotlib- マーカーと線形の使用

より読みやすくするために、ポークしてください:\n\n\nカタログ\n1.マーカー\n 初級マーカー\n 上級マーカー\n ハイ・マスター・マーカー\n ミディアムマーカー

Dec 23, 2020 · 5 min read