Elasticsearch
指標と型の違い
サーチ…
備考
indexがSQLデータベースであるSQLデータベースのテーブルのようなtype sを見るのは簡単です。しかし、これはtype sに近づく良い方法ではありません。
すべてのタイプについて
実際、型は文字通り 、Elasticsearch: _typeによって各ドキュメントに追加された単なるメタデータフィールド_type 。上記の例では、 my_typeとmy_other_type 2種類が作成されています。つまり、型に関連付けられた各ドキュメントには、 "_type": "my_type"ように自動的に定義された余分なフィールドがあります"_type": "my_type" ;これはドキュメントで索引付けされているため、 検索可能またはフィルタ可能なフィールドになりますが、生のドキュメント自体には影響しません。したがって、アプリケーションで気にする必要はありません。
すべてのタイプは同じインデックスに存在するため、同じインデックスに集約されます。ディスクレベルであっても、同じファイルに存在します。第2のタイプを生成する唯一の分離は論理的なものである。固有であるかどうかにかかわらず、すべてのタイプがマッピングに存在する必要があり、それらのマッピングはすべてクラスタ状態で存在する必要があります。これはメモリを消費し、各タイプが動的に更新されると、マッピングが変化するとパフォーマンスが低下します。
したがって、実際に他のタイプを必要としない限り、単一のタイプのみを定義することがベストプラクティスです。複数のタイプが望ましいシナリオを見るのが一般的です。たとえば、車のインデックスがあるとします。複数のタイプで分割すると便利です。
- BMW
- シェビー
- ホンダ
- マツダ
- メルセデス
- 日産
- レンジローバー
- トヨタ
- ...
この方法で、すべての車を検索するか、オンデマンドでメーカーが制限することができます。これら2つの検索の違いは、次のように簡単です。
GET /cars/_search
そして
GET /cars/bmw/_search
Elasticsearchの新しいユーザーにとって明らかでないことは、2番目のフォームが最初のフォームの特殊化であることです。それは文字どおり書き直されます:
GET /cars/_search
{
"query": {
"bool": {
"filter": [
{
"term" : {
"_type": "bmw"
}
}
]
}
}
}
値がbmw _typeフィールドで索引付けされていないすべての文書を単純にbmwます。すべてのドキュメントは_typeフィールドとしてその型で索引付けされるため、これはかなり単純なフィルタとして機能します。どちらの例でも実際の検索が提供されていた場合、フィルタは必要に応じてフル検索に追加されます。
そのため、型が同一であれば、単一の型(この例ではmanufacturerなど)を指定し、それを効果的に無視する方がはるかに優れています。次に、各文書内で、 make という名前のフィールドまたは任意の名前を明示的に指定し、制限したいときはいつでも手動でフィルターを適用します。これにより、マッピングのサイズが1/nに減少します。ここで、 nは別のタイプの数です。そうでなければ単純化されたマッピングの利点のために、各ドキュメントに別のフィールドを追加します。
Elasticsearch 1.xと2.xでは、このようなフィールドは次のように定義する必要があります。
PUT /cars
{
"manufacturer": { <1>
"properties": {
"make": { <2>
"type": "string",
"index": "not_analyzed"
}
}
}
}
- 名前は任意です。
- 名前は任意で、あなたが望むならそれは型名と一致するかもしれません。
Elasticsearch 5.xでは、上記は機能しますが(推奨されません)、より良い方法は以下を使用することです:
PUT /cars
{
"manufacturer": { <1>
"properties": {
"make": { <2>
"type": "keyword"
}
}
}
}
- 名前は任意です。
- 名前は任意で、あなたが望むならそれは型名と一致するかもしれません。
型はインデックス内で控えめに使用する必要があります。通常、インデックスのマッピングを膨らませるためです。あなたは少なくとも1つは持っていなければなりませんが、複数のものを持たなければならないということは何もありません。
よくある質問
- ほとんど同じ2つ(またはそれ以上)のタイプがあり、タイプごとに固有のフィールドがいくつかある場合はどうなりますか?
インデックス・レベルでは、まばらに使用されているいくつかのフィールドとし、他のタイプは偶数フィールドを使用したことがないという意味(共有されていない少数で非スパースフィールドの束を共有する複数の種類の間で使用されているいずれかのタイプに違いはありません(s))。
言い換えれば、種類に関係なく 、まばらに使用されるフィールドはインデックス全体で疎です。スパース性は、それが別のタイプで定義されているという理由だけでインデックスに利益をもたらしません。
これらの型を組み合わせて、別の型フィールドを追加するだけです。
- 別々の型は全く同じ方法でフィールドを定義する必要があるのはなぜですか?
各フィールドは本当にLuceneレベルで1回しか定義されていないので、そこにいくつの型があるかには関係ありません。タイプが全く存在しないという事実は、Elasticsearchの特徴であり、論理的な分離に過ぎない 。
- 別々に定義された同じフィールドを持つ別々の型を定義できますか?
いいえ、ES 2.x以降で行う方法が見つかった場合は、バグレポートを開く必要があります 。前の質問で指摘したように、Luceneはそれらをすべて1つのフィールドとみなしているため、適切に動作させる方法はありません。
ES 1.xはこれを暗黙の要件として残しました。これにより、インデックス内の1つのシャードのマッピングが同じインデックスの別のシャードと実際に異なる条件を作成することができました。これは事実上競合状態であり、予期しない問題につながる可能性があります。
ルールの例外
- 親/子ドキュメントでは 、同じインデックス内で別の型を使用する必要があります。
- 親は1つのタイプで暮らしています。
- 子供は別のタイプで暮らしています(しかし、各子供はその親と同じシャードに住んでいます)。
- 大量のインデックスを作成することが望ましくなく、スパースフィールドの影響が代替案よりも望ましい非常にニッチな使用例。
- たとえば、Elasticsearch監視プラグインMarvel(1.xおよび2.x)またはX-Pack Monitoring(5.x +)は、クラスタ、ノード、インデックス、特定のインデックス(インデックスレベル)の変更をElasticsearch自身で監視します。さらには破片。定義されたマッピングの数が効果的に同じですが、作成したインデックスの数:それはユニークなマッピングを持っているか、それがインデックス(ノートを共有することにより、クラスタの負荷を軽減するために、ベストプラクティスに反する可能性があり、それらの文書を隔離するために、毎日5+インデックスを作成することができます
nから1に減少する)。 - これは高度なシナリオですが、タイプ間で共有フィールドの定義を考慮する必要があります。
- たとえば、Elasticsearch監視プラグインMarvel(1.xおよび2.x)またはX-Pack Monitoring(5.x +)は、クラスタ、ノード、インデックス、特定のインデックス(インデックスレベル)の変更をElasticsearch自身で監視します。さらには破片。定義されたマッピングの数が効果的に同じですが、作成したインデックスの数:それはユニークなマッピングを持っているか、それがインデックス(ノートを共有することにより、クラスタの負荷を軽減するために、ベストプラクティスに反する可能性があり、それらの文書を隔離するために、毎日5+インデックスを作成することができます
型を持つ索引を明示的に作成する
例では、cURLやその他のHTTPアプリケーションに簡単に変換できる基本HTTPを使用しています。また、 Sense構文と一致し、Kibana 5.0のConsoleに名前が変更されます。
注:この例では、部品に注意を促すために<#>を挿入しています。それらをコピーすると削除する必要があります!
PUT /my_index <1>
{
"mappings": {
"my_type": { <2>
"properties": {
"field1": {
"type": "long"
},
"field2": {
"type": "integer"
},
"object1": {
"type": "object",
"properties": {
"field1" : {
"type": "float"
}
}
}
}
}
},
"my_other_type": {
"properties": {
"field1": {
"type": "long" <3>
},
"field3": { <4>
"type": "double"
}
}
}
}
- これは、create indexエンドポイントを使用して
indexを作成しています。 - これは
type作成しています。 - 同じ
index内のtypesの共有フィールドは、同じ定義を共有する必要があります。 ES 1.xは厳密にこの動作を強制しませんでしたが、暗黙の要件でした。 ES 2.x以上ではこの動作が厳密に強制されます。 -
typeの一意のフィールドは大丈夫です。
インデックス(またはインデックス)には型が含まれます。タイプはドキュメントを分離する便利なメカニズムですが、使用する各タイプのマッピングを動的/自動または明示的に定義する必要があります。インデックスに15種類のタイプを定義すると、15の一意のマッピングがあります。
このコンセプトの詳細とタイプを使用するかどうかについては、備考を参照してください。
タイプでインデックスを動的に作成する
例では、cURLやその他のHTTPアプリケーションに簡単に変換できる基本HTTPを使用しています。また、 Sense構文と一致し、Kibana 5.0のConsoleに名前が変更されます。
注:この例では、部品に注意を促すために<#>を挿入しています。それらをコピーすると削除する必要があります!
DELETE /my_index <1>
PUT /my_index/my_type/abc123 <2>
{
"field1" : 1234, <3>
"field2" : 456,
"object1" : {
"field1" : 7.8 <4>
}
}
- 既に存在する場合(前の例のため)、索引を削除します。
- 文書を索引
my_indexに、タイプmy_typeIDabc123(数値でも可能ですが、常に文字列です)に索引付けします。- デフォルトでは、動的索引の作成は、文書を索引付けするだけで有効になります。これは開発環境には最適ですが、本番環境では必ずしも良いとは限りません。
- このフィールドは整数であるため、最初に表示されるときはマッピングする必要があります。 Elasticsearchは常にすべての着信タイプに対して最も広いタイプを想定しているため、
integerまたはshortではなくlongとしてマッピングされます(両方とも1234と456含む可能性があります)。 - このフィールドでも同じことが当てはまります。あなたが望むかもしれないように、
floatではなくdoubleとしてマップされます。
この動的に作成されるインデックスとタイプは、最初の例で定義されたマッピングとほぼ一致します。ただし、 <3>および<4>が自動的に定義されたマッピングにどのように影響するかを理解することは重要です。
同じ索引にさらに別のタイプを動的に追加することで、これを実行できます。
PUT /my_index/my_other_type/abc123 <1>
{
"field1": 91, <2>
"field3": 4.567
}
- タイプは上記の文書との唯一の違いです。 IDは同じで、大丈夫です!これは、他とは関係ありません
abc123同じインデックスであることを起こるということ以外に。 -
field1すでに索引に存在するため、他の型で定義されているフィールドと同じタイプのフィールドでなければなりません 。文字列か整数でない値を"field1": "this is some text"すると失敗します(例"field1": "this is some text"または"field1": 123.0)。
これは、動的のマッピング作成しmy_other_type同じインデックス、内my_index 。
注:Elasticsearchにインデックス時に動的に実行させるのではなく、マッピングを事前に定義する方が常に迅速です。
両方の文書の索引付けの最終結果は、最初の例と似ていますが、フィールドのタイプは異なるため、わずかに無駄です。
GET /my_index/_mappings <1>
{
"mappings": {
"my_type": { <2>
"properties": {
"field1": {
"type": "long"
},
"field2": {
"type": "long" <3>
},
"object1": {
"type": "object",
"properties": {
"field1" : {
"type": "double" <4>
}
}
}
}
}
},
"my_other_type": { <5>
"properties": {
"field1": {
"type": "long"
},
"field3": {
"type": "double"
}
}
}
}
- これは
_mappingsエンドポイントを使用して、作成したインデックスからマッピングを取得します。 - この例の最初のステップでは、
my_typeを動的に作成しmy_typeた。 -
field2は、前もって定義していなかったので、integerではなく、longとなりました。これは 、ディスクストレージでは無駄であることがわかります。 -
object1.field1は#3と同じ理由でdoubleになり、#3と同じ結果になりました。- 技術的には、多くの場合、
long圧縮が可能です。ただし、doubleは浮動小数点数であるため圧縮できません。
- 技術的には、多くの場合、
- この例の2番目のステップでは、
my_other_typeも動的に作成しmy_other_typeた。私たちが既にlongとdoubleを使用していたので、そのマッピングは同じになりました。- ことを覚えておいてください
field1から定義と一致しなければなりませんmy_type(そしてそれがありません)。 -
field3はこのタイプに固有なので、そのような制限はありません。
- ことを覚えておいてください