検索API

検索は、1つ以上のクエリで構成され、これらが組み合わされてElasticsearchに送信されます。検索のクエリに一致するドキュメントは、レスポンスのヒットまたは検索結果として返されます。

検索には、クエリをより良く処理するために使用される追加情報が含まれる場合もあります。たとえば、検索は特定のインデックスに制限されるか、特定の数の結果のみを返すことができます。

検索APIを使用して、Elasticsearchのデータストリームまたはインデックスに保存されたデータを検索および集約できます。APIのqueryリクエストボディパラメータは、Query DSLで記述されたクエリを受け入れます。

検索を実行する

次のリクエストは、matchクエリを使用してmy-index-000001を検索します。このクエリは、user.idの値がkimchyのドキュメントに一致します。

Python

  1. resp = client.search(
  2. index="my-index-000001",
  3. query={
  4. "match": {
  5. "user.id": "kimchy"
  6. }
  7. },
  8. )
  9. print(resp)

Ruby

  1. response = client.search(
  2. index: 'my-index-000001',
  3. body: {
  4. query: {
  5. match: {
  6. 'user.id' => 'kimchy'
  7. }
  8. }
  9. }
  10. )
  11. puts response

Js

  1. const response = await client.search({
  2. index: "my-index-000001",
  3. query: {
  4. match: {
  5. "user.id": "kimchy",
  6. },
  7. },
  8. });
  9. console.log(response);

コンソール

  1. GET /my-index-000001/_search
  2. {
  3. "query": {
  4. "match": {
  5. "user.id": "kimchy"
  6. }
  7. }
  8. }

APIのレスポンスは、hits.hitsプロパティ内のクエリに一致する上位10件のドキュメントを返します。

コンソール-結果

  1. {
  2. "took": 5,
  3. "timed_out": false,
  4. "_shards": {
  5. "total": 1,
  6. "successful": 1,
  7. "skipped": 0,
  8. "failed": 0
  9. },
  10. "hits": {
  11. "total": {
  12. "value": 1,
  13. "relation": "eq"
  14. },
  15. "max_score": 1.3862942,
  16. "hits": [
  17. {
  18. "_index": "my-index-000001",
  19. "_id": "kxWFcnMByiguvud1Z8vC",
  20. "_score": 1.3862942,
  21. "_source": {
  22. "@timestamp": "2099-11-15T14:12:12",
  23. "http": {
  24. "request": {
  25. "method": "get"
  26. },
  27. "response": {
  28. "bytes": 1070000,
  29. "status_code": 200
  30. },
  31. "version": "1.1"
  32. },
  33. "message": "GET /search HTTP/1.1 200 1070000",
  34. "source": {
  35. "ip": "127.0.0.1"
  36. },
  37. "user": {
  38. "id": "kimchy"
  39. }
  40. }
  41. }
  42. ]
  43. }
  44. }

一般的な検索オプション

次のオプションを使用して、検索をカスタマイズできます。

Query DSL

Query DSLは、結果を得るために組み合わせて使用できるさまざまなクエリタイプをサポートしています。クエリタイプには次のものが含まれます:

集約

検索集約を使用して、検索結果の統計やその他の分析を取得できます。集約は、次のような質問に答えるのに役立ちます:

  • サーバーの平均応答時間は?
  • ネットワーク上のユーザーによってヒットされた上位のIPアドレスは?
  • 顧客ごとの総取引収益は?

複数のデータストリームおよびインデックスを検索

カンマ区切りの値とgrepのようなインデックスパターンを使用して、同じリクエストで複数のデータストリームおよびインデックスを検索できます。特定のインデックスからの検索結果をブーストすることもできます。複数のデータストリームおよびインデックスを検索を参照してください。

検索結果をページネート

デフォルトでは、検索は一致する上位10件のヒットのみを返します。より多くまたは少ないドキュメントを取得するには、検索結果をページネートを参照してください。

選択したフィールドを取得

検索レスポンスのhits.hitsプロパティには、各ヒットの完全なドキュメント_sourceが含まれています。_sourceや他のフィールドのサブセットのみを取得するには、選択したフィールドを取得を参照してください。

検索結果をソート

デフォルトでは、検索ヒットは_scoreによってソートされます。これは、各ドキュメントがクエリにどれだけ一致するかを測定する関連スコアです。これらのスコアの計算をカスタマイズするには、script_scoreクエリを使用します。他のフィールド値で検索ヒットをソートするには、検索結果をソートを参照してください。

非同期検索を実行

Elasticsearchの検索は、大量のデータを迅速に処理するように設計されており、しばしばミリ秒単位で結果を返します。このため、検索はデフォルトで同期です。検索リクエストは、完全な結果を待ってからレスポンスを返します。

ただし、大規模なデータセットや複数のクラスターにわたる検索では、完全な結果が得られるまでに時間がかかる場合があります。

長時間の待機を避けるために、非同期またはasync検索を実行できます。非同期検索を使用すると、長時間実行される検索の部分的な結果を今すぐ取得し、後で完全な結果を取得できます。

クエリにのみ存在するフィールドを定義する

データをインデックス化してから検索するのではなく、検索クエリの一部としてのみ存在するランタイムフィールドを定義できます。検索リクエストでruntime_mappingsセクションを指定してランタイムフィールドを定義し、オプションでPainlessスクリプトを含めることができます。

たとえば、次のクエリはday_of_weekというランタイムフィールドを定義します。含まれているスクリプトは、@timestampフィールドの値に基づいて曜日を計算し、emitを使用して計算された値を返します。

クエリには、day_of_weekに対して動作するterms aggregationも含まれています。

Python

  1. resp = client.search(
  2. index="my-index-000001",
  3. runtime_mappings={
  4. "day_of_week": {
  5. "type": "keyword",
  6. "script": {
  7. "source": "emit(doc['@timestamp'].value.dayOfWeekEnum\n .getDisplayName(TextStyle.FULL, Locale.ENGLISH))"
  8. }
  9. }
  10. },
  11. aggs={
  12. "day_of_week": {
  13. "terms": {
  14. "field": "day_of_week"
  15. }
  16. }
  17. },
  18. )
  19. print(resp)

Js

  1. const response = await client.search({
  2. index: "my-index-000001",
  3. runtime_mappings: {
  4. day_of_week: {
  5. type: "keyword",
  6. script: {
  7. source:
  8. "emit(doc['@timestamp'].value.dayOfWeekEnum\n .getDisplayName(TextStyle.FULL, Locale.ENGLISH))",
  9. },
  10. },
  11. },
  12. aggs: {
  13. day_of_week: {
  14. terms: {
  15. field: "day_of_week",
  16. },
  17. },
  18. },
  19. });
  20. console.log(response);

コンソール

  1. GET /my-index-000001/_search
  2. {
  3. "runtime_mappings": {
  4. "day_of_week": {
  5. "type": "keyword",
  6. "script": {
  7. "source":
  8. """emit(doc['@timestamp'].value.dayOfWeekEnum
  9. .getDisplayName(TextStyle.FULL, Locale.ENGLISH))"""
  10. }
  11. }
  12. },
  13. "aggs": {
  14. "day_of_week": {
  15. "terms": {
  16. "field": "day_of_week"
  17. }
  18. }
  19. }
  20. }

レスポンスには、day_of_weekランタイムフィールドに基づく集約が含まれています。bucketsの下には、keyの値がSundaykeyがあります。このクエリは、day_of_weekランタイムフィールドに定義されたスクリプトに基づいてこの値を動的に計算しましたが、フィールドをインデックス化することはありませんでした。

コンソール-結果

  1. {
  2. ...
  3. ***
  4. "aggregations" : {
  5. "day_of_week" : {
  6. "doc_count_error_upper_bound" : 0,
  7. "sum_other_doc_count" : 0,
  8. "buckets" : [
  9. {
  10. "key" : "Sunday",
  11. "doc_count" : 5
  12. }
  13. ]
  14. }
  15. }
  16. }

検索タイムアウト

デフォルトでは、検索リクエストはタイムアウトしません。リクエストは、各シャードから完全な結果を待ってからレスポンスを返します。

非同期検索は長時間実行される検索用に設計されていますが、timeoutパラメータを使用して、各シャードが完了するまで待機する期間を指定することもできます。各シャードは、指定された時間内にヒットを収集します。期間が終了したときに収集が完了していない場合、Elasticsearchはその時点までに蓄積されたヒットのみを使用します。検索リクエストの全体的なレイテンシは、検索に必要なシャードの数と同時シャードリクエストの数に依存します。

Python

  1. resp = client.search(
  2. index="my-index-000001",
  3. timeout="2s",
  4. query={
  5. "match": {
  6. "user.id": "kimchy"
  7. }
  8. },
  9. )
  10. print(resp)

Ruby

  1. response = client.search(
  2. index: 'my-index-000001',
  3. body: {
  4. timeout: '2s',
  5. query: {
  6. match: {
  7. 'user.id' => 'kimchy'
  8. }
  9. }
  10. }
  11. )
  12. puts response

Js

  1. const response = await client.search({
  2. index: "my-index-000001",
  3. timeout: "2s",
  4. query: {
  5. match: {
  6. "user.id": "kimchy",
  7. },
  8. },
  9. });
  10. console.log(response);

コンソール

  1. GET /my-index-000001/_search
  2. {
  3. "timeout": "2s",
  4. "query": {
  5. "match": {
  6. "user.id": "kimchy"
  7. }
  8. }
  9. }

すべての検索リクエストに対してクラスター全体のデフォルトタイムアウトを設定するには、クラスタ設定APIを使用してsearch.default_search_timeoutを構成します。このグローバルタイムアウト期間は、リクエストにtimeout引数が渡されない場合に使用されます。グローバル検索タイムアウトが検索リクエストが完了する前に期限切れになると、リクエストはタスクキャンセルを使用してキャンセルされます。search.default_search_timeout設定のデフォルトは-1(タイムアウトなし)です。

検索キャンセル

タスク管理APIを使用して検索リクエストをキャンセルできます。Elasticsearchは、クライアントのHTTP接続が閉じると自動的に検索リクエストをキャンセルします。検索リクエストが中止またはタイムアウトした場合、HTTP接続を閉じるようにクライアントを設定することをお勧めします。

総ヒット数を追跡

一般的に、すべての一致を訪問せずに総ヒット数を正確に計算することはできません。これは、多くのドキュメントに一致するクエリにとってコストがかかります。track_total_hitsパラメータを使用すると、総ヒット数をどのように追跡するかを制御できます。ヒット数の下限があることがしばしば十分であるため、デフォルトは10,000に設定されています。これは、リクエストが10,000ヒットまで正確に総ヒット数をカウントすることを意味します。特定の閾値を超えた後に正確なヒット数が必要ない場合、検索を高速化するための良いトレードオフです。

  1. #### Python
  2. ``````python
  3. resp = client.search(
  4. index="my-index-000001",
  5. track_total_hits=True,
  6. query={
  7. "match": {
  8. "user.id": "elkbee"
  9. }
  10. },
  11. )
  12. print(resp)
  13. `

Ruby

  1. response = client.search(
  2. index: 'my-index-000001',
  3. body: {
  4. track_total_hits: true,
  5. query: {
  6. match: {
  7. 'user.id' => 'elkbee'
  8. }
  9. }
  10. }
  11. )
  12. puts response

Js

  1. const response = await client.search({
  2. index: "my-index-000001",
  3. track_total_hits: true,
  4. query: {
  5. match: {
  6. "user.id": "elkbee",
  7. },
  8. },
  9. });
  10. console.log(response);

コンソール

  1. GET my-index-000001/_search
  2. {
  3. "track_total_hits": true,
  4. "query": {
  5. "match" : {
  6. "user.id" : "elkbee"
  7. }
  8. }
  9. }

… 返される:

コンソール-結果

  1. {
  2. "_shards": ...
  3. "timed_out": false,
  4. "took": 100,
  5. "hits": {
  6. "max_score": 1.0,
  7. "total" : {
  8. "value": 2048,
  9. "relation": "eq"
  10. },
  11. "hits": ...
  12. }
  13. }
クエリに一致するヒットの総数。
カウントは正確です(例:"eq"は等しいを意味します)。
  1. #### Python
  2. ``````python
  3. resp = client.search(
  4. index="my-index-000001",
  5. track_total_hits=100,
  6. query={
  7. "match": {
  8. "user.id": "elkbee"
  9. }
  10. },
  11. )
  12. print(resp)
  13. `

Ruby

  1. response = client.search(
  2. index: 'my-index-000001',
  3. body: {
  4. track_total_hits: 100,
  5. query: {
  6. match: {
  7. 'user.id' => 'elkbee'
  8. }
  9. }
  10. }
  11. )
  12. puts response

Js

  1. const response = await client.search({
  2. index: "my-index-000001",
  3. track_total_hits: 100,
  4. query: {
  5. match: {
  6. "user.id": "elkbee",
  7. },
  8. },
  9. });
  10. console.log(response);

コンソール

  1. GET my-index-000001/_search
  2. {
  3. "track_total_hits": 100,
  4. "query": {
  5. "match": {
  6. "user.id": "elkbee"
  7. }
  8. }
  9. }

レスポンス内のhits.total.relationは、hits.total.valueで返される値が正確であるか("eq")または総数の下限であるか("gte")を示します。

たとえば、次のレスポンス:

コンソール-結果

  1. {
  2. "_shards": ...
  3. "timed_out": false,
  4. "took": 30,
  5. "hits": {
  6. "max_score": 1.0,
  7. "total": {
  8. "value": 42,
  9. "relation": "eq"
  10. },
  11. "hits": ...
  12. }
  13. }
42ドキュメントがクエリに一致します
カウントは正確です("eq"

… これは、totalで返されるヒット数が正確であることを示しています。

クエリに一致するヒットの総数がtrack_total_hitsに設定された値を超える場合、レスポンス内の総ヒット数は、返された値が下限であることを示します:

コンソール-結果

  1. {
  2. "_shards": ...
  3. "hits": {
  4. "max_score": 1.0,
  5. "total": {
  6. "value": 100,
  7. "relation": "gte"
  8. },
  9. "hits": ...
  10. }
  11. }
クエリに一致するドキュメントが少なくとも100件あります
これは下限です("gte")。

総ヒット数を全く追跡する必要がない場合は、このオプションをfalseに設定することでクエリ時間を改善できます:

Python

  1. resp = client.search(
  2. index="my-index-000001",
  3. track_total_hits=False,
  4. query={
  5. "match": {
  6. "user.id": "elkbee"
  7. }
  8. },
  9. )
  10. print(resp)

Ruby

  1. response = client.search(
  2. index: 'my-index-000001',
  3. body: {
  4. track_total_hits: false,
  5. query: {
  6. match: {
  7. 'user.id' => 'elkbee'
  8. }
  9. }
  10. }
  11. )
  12. puts response

Js

  1. const response = await client.search({
  2. index: "my-index-000001",
  3. track_total_hits: false,
  4. query: {
  5. match: {
  6. "user.id": "elkbee",
  7. },
  8. },
  9. });
  10. console.log(response);

コンソール

  1. GET my-index-000001/_search
  2. {
  3. "track_total_hits": false,
  4. "query": {
  5. "match": {
  6. "user.id": "elkbee"
  7. }
  8. }
  9. }

… 返される:

コンソール-結果

  1. {
  2. "_shards": ...
  3. "timed_out": false,
  4. "took": 10,
  5. "hits": {
  6. "max_score": 1.0,
  7. "hits": ...
  8. }
  9. }
ヒットの総数は不明です。

最後に、リクエストで"track_total_hits"trueに設定することで、正確なカウントを強制できます。

track_total_hitsパラメータは、ヒットカウントの正確さとパフォーマンスをトレードオフすることを可能にします。一般的に、track_total_hitsの値が低いほど、クエリは速くなり、falseが最も速い結果を返します。track_total_hitsをtrueに設定すると、Elasticsearchは正確なヒットカウントを返しますが、Max WAND最適化を無効にするため、クエリパフォーマンスが低下する可能性があります。

一致するドキュメントを迅速に確認

特定のクエリに一致するドキュメントがあるかどうかを知りたいだけの場合は、size0に設定して、検索結果に興味がないことを示すことができます。また、terminate_after1に設定して、最初の一致するドキュメントが見つかったときにクエリの実行を終了できることを示すこともできます(シャードごと)。

Python

  1. resp = client.search(
  2. q="user.id:elkbee",
  3. size="0",
  4. terminate_after="1",
  5. )
  6. print(resp)

Ruby

  1. response = client.search(
  2. q: 'user.id:elkbee',
  3. size: 0,
  4. terminate_after: 1
  5. )
  6. puts response

Js

  1. const response = await client.search({
  2. q: "user.id:elkbee",
  3. size: 0,
  4. terminate_after: 1,
  5. });
  6. console.log(response);

コンソール

  1. GET /_search?q=user.id:elkbee&size=0&terminate_after=1
  1. レスポンスには、`````0`````に設定されていたため、ヒットは含まれません。`````hits.total`````は、`````0`````と等しいか、クエリが早期に終了したときに一致するドキュメントが少なくとも存在したことを示す`````0`````より大きくなります。また、クエリが早期に終了した場合、レスポンス内の`````terminated_early`````フラグは`````true`````に設定されます。一部のクエリは、インデックス統計からヒット数を直接取得できるため、クエリを実行する必要がなく、はるかに速くなります。そのような状況では、ドキュメントは収集されず、返された`````total.hits``````````terminate_after`````より大きく、`````terminated_early``````````false`````に設定されます。
  2. [](#31fa804420aad7728f9ba9f20dc1a9c5)
  3. #### コンソール-結果
  4. ``````console-result
  5. {
  6. "took": 3,
  7. "timed_out": false,
  8. "terminated_early": true,
  9. "_shards": {
  10. "total": 1,
  11. "successful": 1,
  12. "skipped" : 0,
  13. "failed": 0
  14. },
  15. "hits": {
  16. "total" : {
  17. "value": 1,
  18. "relation": "eq"
  19. },
  20. "max_score": null,
  21. "hits": []
  22. }
  23. }
  24. `

レスポンス内のtook時間は、このリクエストが処理にかかったミリ秒を含み、ノードがクエリを受信した後すぐに始まり、すべての検索関連作業が完了するまで続き、上記のJSONがクライアントに返される前の時間を含みます。これは、スレッドプールで待機している時間、クラスター全体での分散検索の実行、およびすべての結果を収集する時間を含みます。