第8章 - 複雑な検索
夜は私が光を探すためにそれを使用し、私の黒い目を与えました。
シンプルなAPIと簡単な検索を知って取得した後、我々はほとんどの使用シナリオを満たすことができました。しかし、非リレーショナルデータベースのデータ文書データは、多くの場合、冗長な分野の多様多種多様です、「記録」を作ります 複雑なデータ構造は、複雑な検索をもたらすことです。だから、休日の前に、この章に入る、私たちは「複雑」なデータ構造として構築したいです。
次の2つのシナリオに分け、シナリオは、複雑なデータ構造にバイアスされ、導入集計クエリ、特定のフィールドに戻り、深いページング、偏向複雑な検索精度にシーン2。
シーン1
同社の従業員を保管、従業員情報は、名前、ジョブ番号、性別、生年月日、仕事、上司、部下、部門会社の時間に、更新時刻、作成時間が含まれています。主キーとしてグローバルにユニークなIDを働いている従業員の数は、従業員だけで直属の上司を持っていますが、より下位の、父と息子はそこにある場合、ドキュメントを介して達成することができます。従業員が複数の部門(特に担当の有力者が複数の部門を果たすことができる)に属していてもよいです。
データの構造
インデックスを作成し、マッピング構造を定義します。
PUT http://localhost:9200/company
{
"mappings":{
"employee":{
"properties":{
"id":{
"type":"keyword"
},
"name":{
"type":"text",
"analyzer":"ik_smart",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
},
"sex":{
"type":"keyword"
},
"age":{
"type":"integer"
},
"birthday":{
"type":"date"
},
"position":{
"type":"text",
"analyzer":"ik_smart",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
},
"level":{
"type":"join",
"relations":{
"superior":"staff",
"staff":"junior"
}
},
"departments":{
"type":"text",
"analyzer":"ik_smart",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
},
"joinTime":{
"type":"date"
},
"modified":{
"type":"date"
},
"created":{
"type":"date"
}
}
}
}
}
データ
次のデータ構造があり、我々はいくつかの重要なデータを構築しました。
- ジョー・スミスは、彼が偉大な指導者だった、会社の会長であるいずれかの部門に属していません。
- ジョン・ドウはジョー・スミス、彼の部下に報告する5または6趙の王、日七、8週間で、彼はマーケティングとR&D部門を提携して、マーケティングやR&Dの担当です。
- 王呉、趙6人の上司はジョー・スミスで、彼は部下を持っていた、彼はマーケティング部門の一部です。
- Sunはジョン・ドウで、彼は部下を持っていた、彼はR&D部門の一部であり、7または8週間上司。
次の表では、より包括的な直感的なデータ:
フルネーム | ジョブ番号 | 性別 | 年齢 | 生年月日 | ポスト | より高いです | 下 | 部門 | 会社の時間に | 変更されました | 作成 |
---|---|---|---|---|---|---|---|---|---|---|---|
ジョー・スミス | 1 | 男性 | 49 | 1970-01-01 | 取締役会会長 | / | ジョン・ドウ | / | 1990-01-01 | 1562167817000 | 1562167817000 |
ジョン・ドウ | 2 | 男性 | 39 | 1980年4月3日 | ゼネラルマネージャー | ジョー・スミス | 王呉、趙6日七、8週間 | マーケティング、研究開発 | 2001年2月2日 | 1562167817000 | 1562167817000 |
王呉 | 3 | 女 | 27 | 1992年9月1日 | セールス | ジョン・ドウ | / | マーケティング | 2010-07-01 | 1562167817000 | 1562167817000 |
趙6 | 4 | 男性 | 29 | 1990年10月10日 | セールス | ジョン・ドウ | / | マーケティング | 2010-08-08 | 1562167817000 | 1562167817000 |
SUN 7 | 5 | 男性 | 26 | 1993年12月10日 | フロントエンドエンジニア | ジョン・ドウ | / | R&D部門 | 2016年7月1日 | 1562167817000 | 1562167817000 |
8週間 | 6 | 男性 | 25 | 1994年5月11日 | Javaのエンジニア | ジョン・ドウ | / | R&D部門 | 2018年3月10日 | 1562167817000 | 1562167817000 |
図6は、データを挿入します。
POST http://localhost:9200/company/employee/1?routing=1
{
"id":"1",
"name":"张三",
"sex":"男",
"age":49,
"birthday":"1970-01-01",
"position":"董事长",
"level":{
"name":"superior"
},
"joinTime":"1990-01-01",
"modified":"1562167817000",
"created":"1562167817000"
}
POST http://localhost:9200/company/employee/2?routing=1
{
"id":"2",
"name":"李四",
"sex":"男",
"age":39,
"birthday":"1980-04-03",
"position":"总经理",
"level":{
"name":"staff",
"parent":"1"
},
"departments":["市场部","研发部"],
"joinTime":"2001-02-02",
"modified":"1562167817000",
"created":"1562167817000"
}
POST http://localhost:9200/company/employee/3?routing=1
{
"id":"3",
"name":"王五",
"sex":"女",
"age":27,
"birthday":"1992-09-01",
"position":"销售",
"level":{
"name":"junior",
"parent":"2"
},
"departments":["市场部"],
"joinTime":"2010-07-01",
"modified":"1562167817000",
"created":"1562167817000"
}
POST http://localhost:9200/company/employee/4?routing=1
{
"id":"4",
"name":"赵六",
"sex":"男",
"age":29,
"birthday":"1990-10-10",
"position":"销售",
"level":{
"name":"junior",
"parent":"2"
},
"departments":["市场部"],
"joinTime":"2010-08-08",
"modified":"1562167817000",
"created":"1562167817000"
}
POST http://localhost:9200/company/employee/5?routing=1
{
"id":"5",
"name":"孙七",
"sex":"男",
"age":26,
"birthday":"1993-12-10",
"position":"前端工程师",
"level":{
"name":"junior",
"parent":"2"
},
"departments":["研发部"],
"joinTime":"2016-07-01",
"modified":"1562167817000",
"created":"1562167817000"
}
POST http://localhost:9200/company/employee/6?routing=1
{
"id":"6",
"name":"周八",
"sex":"男",
"age":28,
"birthday":"1994-05-11",
"position":"Java工程师",
"level":{
"name":"junior",
"parent":"2"
},
"departments":["研发部"],
"joinTime":"2018-03-10",
"modified":"1562167817000",
"created":"1562167817000"
}
検索
- クエリのR&Dスタッフ
GET http://localhost:9200/company/employee/_search
{
"query":{
"match":{
"departments":"研发部"
}
}
}
- R&Dにおけるクエリとマーケティングスタッフで
GET http://localhost:9200/company/employee/_search
{
"query": {
"bool":{
"must":[{
"match":{
"departments":"市场部"
}
},{
"match":{
"departments":"研发部"
}
}]
}
}
}
*検索されるフィールドは、配列型ですが、クエリおよび特別な要件。
- クエリ名=「ジョー・スミス」直属。
GET http://localhost:9200/company/employee/_search
{
"query": {
"has_parent":{
"parent_type":"superior",
"query":{
"match":{
"name":"张三"
}
}
}
}
}
- クエリ名=「ジョン・ドウ」直属。
GET http://localhost:9200/company/employee/_search
{
"query": {
"has_parent":{
"parent_type":"staff",
"query":{
"match":{
"name":"李四"
}
}
}
}
}
- クエリ名=即時に優れた「王5」。
GET http://localhost:9200/company/employee/_search
{
"query": {
"has_child":{
"type":"junior",
"query":{
"match":{
"name":"王五"
}
}
}
}
}
集計クエリ
ES重合クエリのMySQL重合類似した機能(平均、最大、など)は、例えば、従業員の平均年齢を計算します。
GET http://localhost:9200/company/employee/_search?pretty
{
"size": 0,
"aggs": {
"avg_age": {
"avg": {
"field": "age"
}
}
}
}
指定したフィールドをクエリ
指定したフィールドの指定したフィールドがクエリ結果に返される必要がある返します。例えば、唯一のクエリジョー・スミスの誕生日。
GET http://localhost:9200/company/employee/_search?pretty
{
"_source":["name","birthday"],
"query":{
"match":{
"name":"张三"
}
}
}
ディープページネーション
ES深いページングは一般的な問題です。使用済みESはすべて知っている、ESのデフォルトのクエリの深さは、ページが*のpageSize <10000で10,000人以上、ではありません。あなたは、どちらかの最大の深さを設定することで、いずれかの方法で、10,000人以上のデータをチェックする必要がある場合はscroll
、クエリをスクロールします。設定を調整する場合は、チェックアウトすることができさえ、パフォーマンスが悪くなります。しかしによってscroll
クエリに「前」への唯一の道を転がりによって引き起こされる問題、「次へ」操作がジャンプするページ番号を実行することはできません。
scroll
単純な原理に言えば、すべてのデータが終了するまで、調査中のデータの最初のバッチとして調査、データの最後のバッチのグループのグループ、です。
まず、クエリを初期化する必要があります
GET http://localhost:9200/company/employee/_search?scroll=1m
{
"query":{
"match_all":{}
},
"size":1,
"_source": ["id"]
}
クエリとして通常のクエリ結果、スクロールのURLのよう= 1メートルは、有効期限を指し、1分間のカーソルのクエリで、クエリは毎回更新されます、それは会計では長くはありませんあまりにも多くの時間を使います。
そして、あなたはのAPIを経由して返すことができる_scroll_id
以上の結果が返されることを想定し、ローリング問い合わせ"_scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAAFBFk1pNzdFUVhDU3hxX3VtSVFUdDJBWlEAAAAAAAABQhZNaTc3RVFYQ1N4cV91bUlRVHQyQVpRAAAAAAAAAUMWTWk3N0VRWENTeHFfdW1JUVR0MkFaUQAAAAAAAAFEFk1pNzdFUVhDU3hxX3VtSVFUdDJBWlEAAAAAAAABRRZNaTc3RVFYQ1N4cV91bUlRVHQyQVpR"
。
GET http://localhost:9200/_search/scroll
{
"scroll":"1m",
"scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAAFBFk1pNzdFUVhDU3hxX3VtSVFUdDJBWlEAAAAAAAABQhZNaTc3RVFYQ1N4cV91bUlRVHQyQVpRAAAAAAAAAUMWTWk3N0VRWENTeHFfdW1JUVR0MkFaUQAAAAAAAAFEFk1pNzdFUVhDU3hxX3VtSVFUdDJBWlEAAAAAAAABRRZNaTc3RVFYQ1N4cV91bUlRVHQyQVpR"
}
時間をかけて問い合わせがフル問い合わせすべてのデータのために、このクエリ音量を下げ続けることができない期限切れの場合はこのように小さな欠点は、そこにあります。しかし、現実には、そこに長い時間のためのユーザー滞在中のページも、その後、有効期限ページにわたるこの時間を照会することはできません前または次のページをクリックすることです。だから、別の方法で、クエリの範囲があります。
別の暗いページ
仮説を働いている従業員のID番号が昇順にデータがだけにして、我々は、クエリのページングを範囲とすることができるということです。
例えば、最初のクエリID> 0のIDデータが昇順に、データ量が1です。
GET http://localhost:9200/company/employee/_search
{
"query":{
"range":{
"id":{
"gt":0
}
}
},
"size":1,
"sort":{
"id":{
"order":"asc"
}
}
}
これは、データの1 ID = 1つの部分を返します、そして我々は、データの量は依然として1で、データID> 1を照会していきます。
GET http://localhost:9200/company/employee/_search
{
"query":{
"range":{
"id":{
"gt":1
}
}
},
"size":1,
"sort":{
"id":{
"order":"asc"
}
}
}
私たちは、同じ深いページネーションクエリを実行すると、制限が満了する時間がありません。
シーン2
製品を見つけるために商品名の下に、製品データを格納することにより、高い精度を必要とし、結果はクレンザー粉を現れ検索しません。
主に探索問題の精度に関連するこのシナリオので、複雑なデータ構造、唯一のタイトルフィールドを持っていません。
唯一のタイトルとワード既定含むフィールドの定義standard
のインデックスを:
PUT http://localhost:9200/ware_index
{
"mappings": {
"ware": {
"properties": {
"title":{
"type":"text"
}
}
}
}
}
二つのデータを挿入します。
POST http://localhost:9200/ware_index/ware
{
"title":"洗面奶"
}
POST http://localhost:9200/ware_index/ware
{
"title":"面粉"
}
「クレンザー」のキーワード検索:
POST http://localhost:9200/ware_index/ware/_search
{
"query":{
"match":{
"title":"洗面奶"
}
}
}
検索結果は、2つの全く関係のない、それは我々の期待に沿ったもので、明らかではありません結果、「クレンザー」と「小麦粉」を表示されます。
理由単語が章で説明された、text
タイプのデフォルトのトークナイザがされstandard
、それが単語分割のための文字列の中国語の単語を、それは「洗浄」、「顔」、「牛乳」に、「クレンザー」分割されます、「小麦粉は」「ピンク」、「顔」に分割しました match
キーワード検索が分割されます、それは最後の二つは「顔」「洗浄」、「顔」、「牛乳」に分割一致させることができ、また、これらの結果に現れました。だから私たちは言葉が一般的に使用されている間、単語を指定する必要が中国の検索文字列のik_smart
場合、それは、最大の大きさに応じて分割されますik_max_word
、それは最小サイズに合わせて期間を分割します、また、これらの結果を引き起こす可能性があります。
DELETE http://localhost:9200/ware_index
インデックスを削除し、再作成して、タイトルフィールドのためのワードブレーカを指定しますik_smart
。
PUT http://localhost:9200/ware_index
{
"mappings":{
"ware":{
"properties":{
"id":{
"type":"keyword"
},
"title":{
"type":"text",
"analyzer":"ik_smart"
}
}
}
}
}
あなたは「クレンザー」と「小麦粉」を挿入するとその後、「クレンザー」の検索は唯一つの結果です。しかし、この時間は、私たちは、次の2つのデータを挿入します。
POST http://localhost:9200/ware_index/ware
{
"id":"1",
"title":"新希望牛奶"
}
POST http://localhost:9200/ware_index/ware
{
"id":"2",
"title":"春秋上新短袖"
}
「ニューホープミルク」のキーワード検索:
POST http://localhost:9200/ware_index/ware/_search
{
"query":{
"match":{
"title":"新希望牛奶"
}
}
}
検索結果は、単に明らかに第二の「春と秋の新半袖は」私たちが望む結果ではない、2挿入登場しました。中の単語ので、この問題の原因にも問題があるik
シソーラスプラグインは、と何の「新たな希望」という言葉がありません、それはキーワード「新たな希望」「新」と「希望」に分割を検索しますので、 「新しい」言い換えると組み合わされていないにも同様に、「春と秋の新しい半袖」で、それはまた、上記の結果をもたらした、「新」は、単独に分割されています。この問題を解決するには、当然のことができik
、我々はしている場合は、プラグイン「Aニューホープ」単語を追加する単語途中で行われますが、他の方法があります。
フレーズクエリ
match_phrase
、フレーズクエリは、それがアイテム「ニューホープミルク」の単語リストにキーワード「ニューホープのミルク」スプリットを検索すると、結果は検索する必要があり、正確なこれらの語彙と一致し、その位置に対応する。この場合、「ニューホープで、これにより、完全にデータ入力や場所を文書に対応する単語からミルク」match_phrase
クエリ結果を検索する語句、および1つのデータだけ。
POST http://localhost:9200/ware_index/ware/_search
{
"query":{
"match_phrase":{
"title":"新希望牛奶"
}
}
}
これはGoogleの検索結果が、ユーザーを満たしているものの、実際の検索は、多くの場合、このような「ミルク新たな希望」の順であると思われるが、残念ながらに応じてmatch_phrase
要件フレーズ一致文書検索することは必要です用語の正確な一致をし、位置に対応します新たな希望のミルク「という用語と一致するキーワード『それはあるが、』牛乳新たな希望「ミルク新たな希望は「内に解釈される」が、該当する位置が存在しないので、それがどんな結果を検索することはできません。同様に、我々はニューホープのミルク『または』前のキーワードであるため、牛乳、新たな希望が、ニューホープのミルク"結果『を検索することができない』「それはのための検索であるかどうか、ニューホープのミルク」データ」を挿入する場合は、この時点での言葉はアイテムが正確に一致しない後者のキーワードであるため、長期的位置と正確に一致が存在しません。
だから、match_phrase
完璧な結果を達成しません。
フレーズプレフィックスクエリ
match_phrase_prefix
、プレフィックスクエリのMySQLで同様のフレーズ、like "新希望%"
、それは一般的にされたmatch_phrase_prefix
合意は、文書データや一貫性のある位置でのキーワード検索用語を満たし、また、あなたがどんな結果を持っていないだろう「ミルクニューホープ」を検索するとする必要があります。また、私たちが望む結果を達成できませんでした。
最小一致
私たちが望む検索結果に「ニューホープのミルク」〜第2のクエリが、しかし「ミルクニューホープ」のために何もできません。この次のクエリは、私たちが望む結果を達成するために、「完璧」することができます。
マッチングのサンプルクエリ最低の度合いを初めて目:
POST http://localhost:9200/ware_index/ware/_search
{
"query": {
"match": {
"title": {
"query": "新希望牛奶",
"minimum_should_match": "80%"
}
}
}
}
minimum_should_match
それはマッチングの最低の度合いです。「80%」は、それがどういう意味を表しますか?またはキーワードから「ニューホープのミルクは、」「を通じて場合は、3つのキーワードニューホープのミルク『と解釈されるニューホープのミルク」』の前に言った、開始するにはどのようなアイテムいくつかの単語に解析されmatch
、新しい検索、含まれています」 「データも検索結果に表示されます。用語の意味の「80%」は3×3と少なくとも80%一致している必要があります= 2.4語彙項目が検索結果に表示される、2個、少なくとも2を含む検索語に必要な、すなわちデータに切り捨てアイテム。明らかに、「春と秋の新半袖」一つだけの単語項目は、満たしていない場合の最小一致要件の二つの用語を、それが検索結果に表示されません。
上記の検索の結果である場合には同様に、「牛乳ニューホープ、」それは、フレーズ一致ではありませんので、それは同じ語彙項目にマッチした場所を必要としません。
あれば、導入することができる"minimum_should_match":"100%"
データがあることが必要ですことが必要とされる完全一致、すべての語彙項目が含まれていますが、とても少ない検索結果が表示されます。場合"minimun_should_match:0"
この場合は含めることはできません語彙項目を表すものではありませんが、ちょうど持っています用語が検索結果に表示することができ、実際には、デフォルトでmatch
検索、それはより多くの検索結果が表示されます。
あまりない、役に立たない検索結果よりもないより、私たちはシーンのほとんどを満たすために、「80%」に設定し、より良い28件の原則に基づいて経験だけでなく、実践番組を持つことができ、適切な値を探します。
第IX章-Javaクライアント(下)
基づいてJavaクライアント(上)、この記事では、SpringデータElasticSearchプロジェクトを作成する方法に入り、またあまりにも多くの物語を行うことはありません。ソースコード、ソースアドレスを使用する方が必ずとhttps://github.com/yu-linfeng/elasticsearch6.x_tutorial/tree/master/code/spring-data-elasticsearchに、特定のコードのディレクトリをcomplex
パッケージ。
この章のコードはどのようにするJava APIの合格する方法に焦点を当てて組み合わせるようにしてください文書の父と息子だけでなく、クエリにデータを。
データへの文書の息子
ESドキュメントの保存形式で父と息子が実際にあるのキーマッピングマッピングを定義するときに存在、例えば、我々は次のように定義されたサブ文書になります。
{
......
"level":{
"type":"join",
"relations":{
"superior":"staff",
"staff":"junior"
}
}
......
}
データの一部を書き込む場合:
{
......
"level":{
"name":"staff",
"parent":"1"
}
......
}
Javaでのエンティティのために、私たちはできるlevel
ためにフィールドMap<String, Object>
を入力します。春データElasticSearchを使用しているとき、私たちは直接呼び出すことができないことに注意すべきキーsava
またはsaveAll
方法。ES規定父と息子のドキュメントが同じスライスに属している必要があり、それは、サブ文書を書くとき、あなたが定義する必要があると言うことですrouting
パラメータを。ここでのコードの抜粋は以下のとおりです。
BulkRequestBuilder bulkRequestBuilder = client.prepareBulk();
bulkRequestBuilder.add(client.prepareIndex("company", "employee", employeePO.getId()).setRouting(routing).setSource(mapper.writeValueAsString(employeePO), XContentType.JSON)).execute().actionGet();
リファレンスソースを一緒に使用する必要があります。
ESは本当に非常に強力な検索エンジンです。限られた容量、それは一例ずつを説明するためのJava APIのすべてのことができない、あなたがコードを書く場合には、作者の難しメールボックスまでご連絡くださいOutlook.com AT hellobugを、または公衆番号でcoderbuff、我々はいくつかの答えへの回答を得た、答えることができません一緒に答えます。
いいえ国民の関心ん:CoderBuff、返信「ES」は「ElasticSearch6.x戦闘チュートリアル」PDFのフルバージョンを取得します。