インデックスソート

Elasticsearchで新しいインデックスを作成する際、各シャード内のセグメントがどのようにソートされるかを設定することができます。デフォルトでは、Luceneはソートを適用しません。index.sort.*設定は、各セグメント内のドキュメントをソートするために使用されるフィールドを定義します。

ネストされたオブジェクトを持つマッピングにインデックスソートを適用することは許可されていますが、index.sort.*設定にネストされたフィールドが含まれていない必要があります。

例えば、以下の例は単一のフィールドでソートを定義する方法を示しています:

Python

  1. resp = client.indices.create(
  2. index="my-index-000001",
  3. settings={
  4. "index": {
  5. "sort.field": "date",
  6. "sort.order": "desc"
  7. }
  8. },
  9. mappings={
  10. "properties": {
  11. "date": {
  12. "type": "date"
  13. }
  14. }
  15. },
  16. )
  17. print(resp)

Ruby

  1. response = client.indices.create(
  2. index: 'my-index-000001',
  3. body: {
  4. settings: {
  5. index: {
  6. 'sort.field' => 'date',
  7. 'sort.order' => 'desc'
  8. }
  9. },
  10. mappings: {
  11. properties: {
  12. date: {
  13. type: 'date'
  14. }
  15. }
  16. }
  17. }
  18. )
  19. puts response

Js

  1. const response = await client.indices.create({
  2. index: "my-index-000001",
  3. settings: {
  4. index: {
  5. "sort.field": "date",
  6. "sort.order": "desc",
  7. },
  8. },
  9. mappings: {
  10. properties: {
  11. date: {
  12. type: "date",
  13. },
  14. },
  15. },
  16. });
  17. console.log(response);

コンソール

  1. PUT my-index-000001
  2. {
  3. "settings": {
  4. "index": {
  5. "sort.field": "date",
  6. "sort.order": "desc"
  7. }
  8. },
  9. "mappings": {
  10. "properties": {
  11. "date": {
  12. "type": "date"
  13. }
  14. }
  15. }
  16. }
このインデックスはdateフィールドでソートされています
… 降順で。

インデックスを複数のフィールドでソートすることも可能です:

Python

  1. resp = client.indices.create(
  2. index="my-index-000001",
  3. settings={
  4. "index": {
  5. "sort.field": [
  6. "username",
  7. "date"
  8. ],
  9. "sort.order": [
  10. "asc",
  11. "desc"
  12. ]
  13. }
  14. },
  15. mappings={
  16. "properties": {
  17. "username": {
  18. "type": "keyword",
  19. "doc_values": True
  20. },
  21. "date": {
  22. "type": "date"
  23. }
  24. }
  25. },
  26. )
  27. print(resp)

Ruby

  1. response = client.indices.create(
  2. index: 'my-index-000001',
  3. body: {
  4. settings: {
  5. index: {
  6. 'sort.field' => [
  7. 'username',
  8. 'date'
  9. ],
  10. 'sort.order' => [
  11. 'asc',
  12. 'desc'
  13. ]
  14. }
  15. },
  16. mappings: {
  17. properties: {
  18. username: {
  19. type: 'keyword',
  20. doc_values: true
  21. },
  22. date: {
  23. type: 'date'
  24. }
  25. }
  26. }
  27. }
  28. )
  29. puts response

Js

  1. const response = await client.indices.create({
  2. index: "my-index-000001",
  3. settings: {
  4. index: {
  5. "sort.field": ["username", "date"],
  6. "sort.order": ["asc", "desc"],
  7. },
  8. },
  9. mappings: {
  10. properties: {
  11. username: {
  12. type: "keyword",
  13. doc_values: true,
  14. },
  15. date: {
  16. type: "date",
  17. },
  18. },
  19. },
  20. });
  21. console.log(response);

コンソール

  1. PUT my-index-000001
  2. {
  3. "settings": {
  4. "index": {
  5. "sort.field": [ "username", "date" ],
  6. "sort.order": [ "asc", "desc" ]
  7. }
  8. },
  9. "mappings": {
  10. "properties": {
  11. "username": {
  12. "type": "keyword",
  13. "doc_values": true
  14. },
  15. "date": {
  16. "type": "date"
  17. }
  18. }
  19. }
  20. }
このインデックスは最初にusernameでソートされ、その後dateでソートされます
usernameフィールドは昇順で、dateフィールドは降順で。

インデックスソートは以下の設定をサポートします:

  • index.sort.field
  • インデックスをソートするために使用されるフィールドのリスト。ここではbooleannumericdate、およびkeywordフィールドがdoc_valuesを持つことが許可されています。
  • index.sort.order
  • 各フィールドに使用するソート順。順序オプションは以下の値を持つことができます:
    • asc:昇順
    • desc:降順。
  • index.sort.mode
  • Elasticsearchは多値フィールドによるソートをサポートしています。モードオプションは、ドキュメントをソートするために選択される値を制御します。モードオプションは以下の値を持つことができます:
    • min:最小値を選択。
    • max:最大値を選択。
  • index.sort.missing
  • missingパラメータは、フィールドが欠落しているドキュメントがどのように扱われるかを指定します。missing値は以下の値を持つことができます:
    • _last:フィールドに値がないドキュメントは最後にソートされます。
    • _first:フィールドに値がないドキュメントは最初にソートされます。

インデックスソートはインデックス作成時にのみ一度定義できます。既存のインデックスにソートを追加または更新することは許可されていません。インデックスソートは、ドキュメントがフラッシュおよびマージ時にソートされる必要があるため、インデックススループットにコストがかかります。この機能を有効にする前に、アプリケーションへの影響をテストする必要があります。

検索リクエストの早期終了

デフォルトでは、Elasticsearchの検索リクエストは、指定されたソートでソートされた上位のドキュメントを取得するために、クエリに一致するすべてのドキュメントを訪問する必要があります。しかし、インデックスソートと検索ソートが同じである場合、N個の上位ランクのドキュメントをグローバルに取得するために、各セグメントで訪問する必要があるドキュメントの数を制限することが可能です。例えば、タイムスタンプフィールドでソートされたイベントを含むインデックスがあるとしましょう:

Python

  1. resp = client.indices.create(
  2. index="events",
  3. settings={
  4. "index": {
  5. "sort.field": "timestamp",
  6. "sort.order": "desc"
  7. }
  8. },
  9. mappings={
  10. "properties": {
  11. "timestamp": {
  12. "type": "date"
  13. }
  14. }
  15. },
  16. )
  17. print(resp)

Ruby

  1. response = client.indices.create(
  2. index: 'events',
  3. body: {
  4. settings: {
  5. index: {
  6. 'sort.field' => 'timestamp',
  7. 'sort.order' => 'desc'
  8. }
  9. },
  10. mappings: {
  11. properties: {
  12. timestamp: {
  13. type: 'date'
  14. }
  15. }
  16. }
  17. }
  18. )
  19. puts response

Js

  1. const response = await client.indices.create({
  2. index: "events",
  3. settings: {
  4. index: {
  5. "sort.field": "timestamp",
  6. "sort.order": "desc",
  7. },
  8. },
  9. mappings: {
  10. properties: {
  11. timestamp: {
  12. type: "date",
  13. },
  14. },
  15. },
  16. });
  17. console.log(response);

コンソール

  1. PUT events
  2. {
  3. "settings": {
  4. "index": {
  5. "sort.field": "timestamp",
  6. "sort.order": "desc"
  7. }
  8. },
  9. "mappings": {
  10. "properties": {
  11. "timestamp": {
  12. "type": "date"
  13. }
  14. }
  15. }
  16. }
このインデックスはタイムスタンプで降順にソートされています(最新が最初)

最後の10件のイベントを検索するには:

Python

  1. resp = client.search(
  2. index="events",
  3. size=10,
  4. sort=[
  5. {
  6. "timestamp": "desc"
  7. }
  8. ],
  9. )
  10. print(resp)

Ruby

  1. response = client.search(
  2. index: 'events',
  3. body: {
  4. size: 10,
  5. sort: [
  6. {
  7. timestamp: 'desc'
  8. }
  9. ]
  10. }
  11. )
  12. puts response

Js

  1. const response = await client.search({
  2. index: "events",
  3. size: 10,
  4. sort: [
  5. {
  6. timestamp: "desc",
  7. },
  8. ],
  9. });
  10. console.log(response);

コンソール

  1. GET /events/_search
  2. {
  3. "size": 10,
  4. "sort": [
  5. { "timestamp": "desc" }
  6. ]
  7. }

Elasticsearchは、各セグメントの上位ドキュメントがすでにインデックスでソートされていることを検出し、各セグメントごとに最初のNドキュメントのみを比較します。クエリに一致する他のドキュメントは、結果の総数をカウントし、集計を構築するために収集されます。

最後の10件のイベントのみを探していて、クエリに一致するドキュメントの総数には興味がない場合は、track_total_hitsをfalseに設定できます:

Python

  1. resp = client.search(
  2. index="events",
  3. size=10,
  4. sort=[
  5. {
  6. "timestamp": "desc"
  7. }
  8. ],
  9. track_total_hits=False,
  10. )
  11. print(resp)

Ruby

  1. response = client.search(
  2. index: 'events',
  3. body: {
  4. size: 10,
  5. sort: [
  6. {
  7. timestamp: 'desc'
  8. }
  9. ],
  10. track_total_hits: false
  11. }
  12. )
  13. puts response

Js

  1. const response = await client.search({
  2. index: "events",
  3. size: 10,
  4. sort: [
  5. {
  6. timestamp: "desc",
  7. },
  8. ],
  9. track_total_hits: false,
  10. });
  11. console.log(response);

コンソール

  1. GET /events/_search
  2. {
  3. "size": 10,
  4. "sort": [
  5. { "timestamp": "desc" }
  6. ],
  7. "track_total_hits": false
  8. }
インデックスソートが上位ドキュメントをランク付けするために使用され、各セグメントは最初の10件の一致後にコレクションを早期終了します。

この場合、Elasticsearchはドキュメントの数をカウントしようとせず、各セグメントでN件のドキュメントが収集されるとすぐにクエリを終了できるようになります。

コンソール-結果

  1. {
  2. "_shards": ...
  3. "hits" : {
  4. "max_score" : null,
  5. "hits" : []
  6. },
  7. "took": 20,
  8. "timed_out": false
  9. }
クエリに一致するヒットの総数は早期終了のため不明です。

集計は、track_total_hitsの値に関係なく、クエリに一致するすべてのドキュメントを収集します。