概要
マッピングには、以下の定義が必要です。
- どのエンティティをインデックスにマッピングするか
- 各エンティティ型について、オブジェクトグラフのどの部分をドキュメントに含めるか
- どの文字列プロパティが実際には
codes
であり、分析すべきでないか - どの文字列プロパティに対して検索とソートのために
分析済み
とraw
の両方のフィールドが必要か - ElasticSearch固有の追加のマッピング
@DocStore - マッピング対象のエンティティ
ElasticSearchインデックスにマッピングしたい各エンティティに@DocStore
アノテーションを追加します。
// Store contact in ElasticSearch
@DocStore
@Entity
public class Contact {
デフォルトでは、@DocStoreは次の意味を持ちます。
- @OneToManyおよび@ManyToManyは含まれません
- @ManyToOneおよび@OneToOneは関連する@Idプロパティのみを含めます
- その他すべての永続プロパティはドキュメントに含まれます
doc
を介して含めるプロパティを指定することで、インデックスに含めるプロパティを効果的に削減できます。
例: 一部のプロパティのみをインデックス化する
@DocStore(doc="firstName, lastName, email")
@Entity
public class Contact {
...
上記のようにインデックス化するプロパティを減らすことは比較的まれであると予想されます。TODO: @DocIgnoreと@DocProperty(ignore=true)のサポートを追加します。
@DocEmbedded - 埋め込みドキュメント
@ManyToOneおよび@OneToManyプロパティでは、@DocEmbedded
を使用してインデックス化されるドキュメントに含めるプロパティを指定できます。
例: 埋め込みManyToOne
顧客ID、名前を連絡先インデックスに埋め込みます。
@DocStore
@Entity
public class Contact {
...
// denormalise including the customer id and name
// into the 'contact' document
@DocEmbedded(doc="id,name")
@ManyToOne(optional=false)
Customer customer;
例: 埋め込みOneToMany
一部の顧客詳細(顧客IDと名前)を埋め込みます。注文詳細を埋め込みます(@OneToManyなので、ElasticSearchの「ネスト」プロパティとして)。
@DocStore
@Entity
public class Order {
...
@DocEmbedded(doc="id,name")
@ManyToOne(optional=false)
Customer customer;
@DocEmbedded
@OneToMany(cascade = CascadeType.ALL, mappedBy = "order")
List<OrderDetail> details;
例: ネストによる埋め込み
ネストされたbillingAddressとbillingAddress.countryを含む、より多くの顧客の詳細を埋め込みます。ID、SKU、名前を含むネストされたproductを含む、より多くの注文の詳細を埋め込みます。
@DocStore
@Entity
public class Order {
...
// embed some customer details including the billingAddress
@DocEmbedded(doc = "id,name,status,billingAddress(*,country(*))")
@ManyToOne(optional=false)
Customer customer;
@DocEmbedded(doc = "*,product(id,sku,name)")
@OneToMany(cascade = CascadeType.ALL, mappedBy = "order")
List<OrderDetail> details;
@DocCode - "コード"である文字列
一部の文字列プロパティを@DocCode
でマッピングして、プロパティ値が分析されず、代わりにリテラル値/コードとして扱われるようにしたいと考えています(アナライザーによって小文字化/ステミングされないなど)。
Ebeanは、UUID
、Enum
、および任意の文字列@Id
プロパティを自動的に「コード」として扱い、これらに@DocCode
でアノテーションを付ける必要はありません。
product skuに@DocCodeを付けると、それが埋め込まれている場所でもコードと見なされることに注意してください。したがって、product skuが注文インデックスに埋め込まれている場合、そこでも@DocCodeプロパティと見なされます。
例
product sku値をリテラルコードとして扱いたい(分析しない)。
@DocStore
@Entity
public class Product {
// treat sku as a "code" (not analysed)
@DocCode
String sku;
@DocSortable
String name;
マッピング
@DocCodeプロパティは、分析されないものとしてマッピングされます。
"properties" : {
"sku": { "type": "string", "index": "not_analyzed" },
...
@DocSortable - 分析済みと未分析
一部の文字列プロパティに@DocSortable
でアノテーションを付けたいと考えています。これにより、プロパティに分析済みと未分析/rawの両方のフィールドが提供されます。分析済みフィールドをテキスト検索に使用し、未分析/rawフィールドをソートに使用できます(およびElasticSearch集計機能)。
customer nameに@DocSortableを付けると、それが埋め込まれている場所でもソート可能と見なされることに注意してください。したがって、customer nameが注文インデックスに埋め込まれている場合、そこでも@DocSortableと見なされます。
例: 顧客
顧客名でソートできるようにしたい。
@DocStore
@Entity
public class Customer {
...
@DocSortable
String name;
例: 製品
製品名でソートできるようにしたい(そして、製品SKUはコードなのでソートできます)。
@DocStore
@Entity
public class Product {
@DocCode
String sku;
@DocSortable
String name;
マッピング
@DocSortableプロパティは、追加の「raw」未分析フィールドでマッピングされます。
"properties" : {
"name": { "type": "string", "fields": {
"raw": { "type": "string", "index": "not_analyzed" } } },
...
クエリの使用 - order by
Ebeanクエリを作成し、order by句を指定すると、Ebeanはorder by句を自動的に変換して、関連する「raw」フィールドがある場合はそれを使用します。
List<Product> products = server.find(Product.class)
.setUseDocStore(true)
.order().asc("name")
.findList();
Elasticクエリ
// name.raw used automatically for sort order
{"sort":[{"name.raw":{"order":"asc"}}],"query":{"match_all":{}}}
クエリの使用 - Term式
「等しい」はElasticの「term」クエリに変換され、@DocSortableプロパティの場合、term式は関連する「raw」フィールドを使用します。
同様に、「より大きい」、「より小さい」、「以上」、「以下」も、利用可能な場合は「raw」フィールドも使用する範囲クエリに変換されます。
List<Product> products = server.find(Product.class)
.setUseDocStore(true)
.where().eq("name","Chair")
.findList();
Elasticクエリ
// name.raw used automatically for 'term' expression
{"query":{"filtered":{"filter":{"term":{"name.raw":"Chair"}}}}}
@DocProperty
@DocProperty
は、次の追加のマッピングオプションをすべて提供します。
store
デフォルト: falseboost
デフォルト: 1includeInAll
デフォルト: trueenabled
デフォルト: truenorms
デフォルト: truedocValues
デフォルト: truenullValue
analyzer
searchAnalyzer
copyTo
index options
- DOCS、FREQS、POSITIONS、OFFSETS
また、@DocCode
および@DocSortable
の代わりに、code
およびsortable
を設定するフラグも提供します。
@DocProperty
は、プロパティまたは@DocStore mapping
属性に設定できます。ここでのマッピングは、既存のプロパティマッピングを効果的にオーバーライドします。
@DocStore(mapping = {
@DocMapping(name = "description",
options = @DocProperty(enabled = false)),
@DocMapping(name = "notes",
options = @DocProperty(boost = 1.5f, store = true))
})
@Entity
public class Content {
マッピングの生成
比較的構造化されたORMドキュメントでElasticSearchを効果的に使用するには、適切なプロパティマッピング(型、コード、ソート可能など)を持つElasticSearchインデックスを作成する必要があります。これは、SQLデータベースのDDLに似ています。
ebean.docstore.generateMapping=true
ebean.docstore.generateMapping=true
の場合、Ebeanは、マッピングされた各Bean型(@DocStore付き)に対してマッピングファイルを生成します。デフォルトでは、これらのマッピングファイルはsrc/main/resources
、次にelastic-mapping
に入り、これはDocStoreConfig pathToResourcesとmappingPathを介して構成可能です。
これは、開発/テスト中に使用されることが期待されています。
ebean.docstore.dropCreate=true
ebean.docstore.dropCreate=true
の場合、Ebeanは起動時に、マッピングされたすべてのインデックスを削除し、生成されたマッピングを使用して再作成します。
これは、開発/テスト中に使用されることが期待されています。
ebean.docstore.create=true
ebean.docstore.create=true
の場合、Ebeanは起動時に、どのインデックスが存在するかを確認し、生成されたマッピングを使用して不足しているものをすべて作成します。
これは、開発/テスト中に使用されることが期待されています。
create=true
を使用するのは、dropCreate
がfalseの場合のみであることに注意してください。
マッピングの例
例のアプリケーションの生成されたマッピングの例は、src/main/resources/elastic-mappingにあります。
例: product_v1.mapping.json
{
"mappings" : {
"product" : {
"properties" : {
"sku": { "type": "string", "fields": { "raw": { "type": "string", "index": "not_analyzed" } } },
"name": { "type": "string", "fields": { "raw": { "type": "string", "index": "not_analyzed" } } },
"whenCreated": { "type": "date" },
"whenModified": { "type": "date" },
"version": { "type": "long" }
}
}
}
}
例: customer_v1.mapping.json
{
"mappings" : {
"customer" : {
"properties" : {
"status": { "type": "string", "index": "not_analyzed" },
"name": { "type": "string" },
"smallNote": { "type": "string" },
"anniversary": { "type": "date" },
"billingAddress" : {
"properties" : {
"id": { "type": "long" },
"line1": { "type": "string" },
"line2": { "type": "string" },
"city": { "type": "string" },
"country" : {
"properties" : {
"code": { "type": "string", "index": "not_analyzed" },
"name": { "type": "string" }
}
},
"whenCreated": { "type": "date" },
"whenModified": { "type": "date" },
"version": { "type": "long" }
}
},
"shippingAddress" : {
"properties" : {
"id": { "type": "long" },
"line1": { "type": "string" },
"line2": { "type": "string" },
"city": { "type": "string" },
"country" : {
"properties" : {
"code": { "type": "string", "index": "not_analyzed" },
"name": { "type": "string" }
}
},
"whenCreated": { "type": "date" },
"whenModified": { "type": "date" },
"version": { "type": "long" }
}
},
"whenCreated": { "type": "date" },
"whenModified": { "type": "date" },
"version": { "type": "long" }
}
}
}
}