Spec-Zone.ru › Elasticsearch 8
›Руководство по Elasticsearch [8.17] ›Поиск данных

API поиска

Поиск состоит из одного или нескольких запросов, которые объединяются и отправляются в Elasticsearch. Документы, соответствующие запросам поиска, возвращаются в поле хитов, или результатов поиска, ответа.

Поиск также может содержать дополнительную информацию, используемую для лучшей обработки запросов. Например, поиск может быть ограничен определенным индексом или возвращать только определенное количество результатов.

Вы можете использовать API поиска, чтобы искать и агрегировать данные, хранящиеся в потоках данных или индексах Elasticsearch. Параметр запроса query тела запроса принимает запросы, написанные в Query DSL.

Выполнение поиска

Следующий запрос выполняет поиск my-index-000001, используя запрос match. Этот запрос соответствует документам со значением поля user.id равным kimchy.

resp = client.search(
    index="my-index-000001",
    query={
        "match": {
            "user.id": "kimchy"
        }
    },
)
print(resp)
response = client.search(
  index: 'my-index-000001',
  body: {
    query: {
      match: {
        'user.id' => 'kimchy'
      }
    }
  }
)
puts response
const response = await client.search({
  index: "my-index-000001",
  query: {
    match: {
      "user.id": "kimchy",
    },
  },
});
console.log(response);
GET /my-index-000001/_search
{
  "query": {
    "match": {
      "user.id": "kimchy"
    }
  }
}

Ответ API возвращает 10 лучших документов, соответствующих запросу, в свойстве hits.hits.

{
  "took": 5,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 1.3862942,
    "hits": [
      {
        "_index": "my-index-000001",
        "_id": "kxWFcnMByiguvud1Z8vC",
        "_score": 1.3862942,
        "_source": {
          "@timestamp": "2099-11-15T14:12:12",
          "http": {
            "request": {
              "method": "get"
            },
            "response": {
              "bytes": 1070000,
              "status_code": 200
            },
            "version": "1.1"
          },
          "message": "GET /search HTTP/1.1 200 1070000",
          "source": {
            "ip": "127.0.0.1"
          },
          "user": {
            "id": "kimchy"
          }
        }
      }
    ]
  }
}

Общие параметры поиска

Вы можете использовать следующие параметры для настройки своих поисков.

Query DSL
Query DSL поддерживает различные типы запросов, которые вы можете комбинировать для получения нужных результатов. Типы запросов включают:

  • Булевый и другие составные запросы, которые позволяют объединять запросы и соответствовать результатам на основе нескольких критериев
  • Запросы на уровне терминов для фильтрации и поиска точных совпадений
  • Запросы на весь текст, которые часто используются в поисковых системах
  • Географические и пространственные запросы

Агрегации
Вы можете использовать агрегации поиска, чтобы получить статистику и другую аналитику для результатов поиска. Агрегации помогают ответить на вопросы, такие как:

  • Каково среднее время отклика моих серверов?
  • Какие IP-адреса чаще всего посещают пользователи моей сети?
  • Какой общий доход от транзакций по клиентам?

Поиск по нескольким потокам данных и индексам
Вы можете использовать значения, разделенные запятыми, и шаблоны индексов наподобие grep, чтобы искать в нескольких потоках данных и индексах в одном запросе. Вы даже можете повышать результаты поиска из определенных индексов. См. Поиск по нескольким потокам данных и индексам с помощью запроса.

Стрёмка результатов поиска
По умолчанию поиски возвращают только 10 совпадающих хитов. Для получения большего или меньшего количества документов см. Стрёмка результатов поиска.

Получение выбранных полей
Свойство hits.hits ответа поиска включает полные данные документа _source для каждого хита. Чтобы получить только подмножество _source или других полей, см. Получение выбранных полей.

Сортировка результатов поиска
По умолчанию хиты поиска сортируются по _score, рейтингу релевантности, который измеряет, насколько хорошо каждый документ соответствует запросу. Для настройки расчёта этих рейтингов используйте запрос script_score. Чтобы сортировать хиты поиска по другим значениям полей, см. Сортировка результатов поиска.

Выполнение асинхронного поиска
Поиски Elasticsearch предназначены для быстрого выполнения на больших объёмах данных, часто возвращая результаты за миллисекунды. По этой причине поиски по умолчанию синхронные. Запрос ожидает полных результатов перед возвращением ответа.

Однако полные результаты могут занимать больше времени для поисков по большим наборам данных или нескольких кластеров.

Чтобы избежать длительных ожиданий, можно выполнить асинхронный, или async, поиск вместо этого. Асинхронный поиск позволяет получить частичные результаты для длительного поиска сейчас и получить полные результаты позже.

Определение полей, существующих только в запросе

Вместо индексирования данных и затем поиска по ним, вы можете определить поля во время выполнения, которые существуют только в рамках запроса поиска. Для определения поля во время выполнения в запросе поиска вы указываете секцию runtime_mappings, которая может включать скрипт Painless.

Например, следующий запрос определяет поле во время выполнения под названием day_of_week. Включённый скрипт вычисляет день недели на основе значения поля @timestamp и использует emit для возвращения вычисленного значения.

Запрос также включает агрегацию terms, которая работает с day_of_week.

resp = client.search(
    index="my-index-000001",
    runtime_mappings={
        "day_of_week": {
            "type": "keyword",
            "script": {
                "source": "emit(doc['@timestamp'].value.dayOfWeekEnum\n        .getDisplayName(TextStyle.FULL, Locale.ENGLISH))"
            }
        }
    },
    aggs={
        "day_of_week": {
            "terms": {
                "field": "day_of_week"
            }
        }
    },
)
print(resp)
const response = await client.search({
  index: "my-index-000001",
  runtime_mappings: {
    day_of_week: {
      type: "keyword",
      script: {
        source:
          "emit(doc['@timestamp'].value.dayOfWeekEnum\n        .getDisplayName(TextStyle.FULL, Locale.ENGLISH))",
      },
    },
  },
  aggs: {
    day_of_week: {
      terms: {
        field: "day_of_week",
      },
    },
  },
});
console.log(response);
GET /my-index-000001/_search
{
  "runtime_mappings": {
    "day_of_week": {
      "type": "keyword",
      "script": {
        "source":
        """emit(doc['@timestamp'].value.dayOfWeekEnum
        .getDisplayName(TextStyle.FULL, Locale.ENGLISH))"""
      }
    }
  },
  "aggs": {
    "day_of_week": {
      "terms": {
        "field": "day_of_week"
      }
    }
  }
}

Ответ включает агрегацию, основанную на поле во время выполнения day_of_week. Под buckets находится значение key со значением Sunday. Запрос динамически вычислил это значение на основе скрипта, определённого в поле во время выполнения day_of_week, без его индексирования.

{
  ...
  ***
  "aggregations" : {
    "day_of_week" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "Sunday",
          "doc_count" : 5
        }
      ]
    }
  }
}

Таймаут поиска

По умолчанию запросы поиска не имеют таймаута. Запрос ожидает полных результатов от каждого фрагмента перед возвращением ответа.

Хотя асинхронный поиск предназначен для длительных поисков, вы также можете использовать параметр timeout для указания времени ожидания завершения каждого фрагмента. Каждый фрагмент собирает хиты в течение указанного периода. Если сборка не завершается, когда период заканчивается, Elasticsearch использует только собранные до этого момента хиты. Общее время ожидания запроса поиска зависит от количества фрагментов, необходимых для поиска, и количества одновременных запросов к фрагментам.

resp = client.search(
    index="my-index-000001",
    timeout="2s",
    query={
        "match": {
            "user.id": "kimchy"
        }
    },
)
print(resp)
response = client.search(
  index: 'my-index-000001',
  body: {
    timeout: '2s',
    query: {
      match: {
        'user.id' => 'kimchy'
      }
    }
  }
)
puts response
const response = await client.search({
  index: "my-index-000001",
  timeout: "2s",
  query: {
    match: {
      "user.id": "kimchy",
    },
  },
});
console.log(response);
GET /my-index-000001/_search
{
  "timeout": "2s",
  "query": {
    "match": {
      "user.id": "kimchy"
    }
  }
}

Для установки глобального таймаута для всех запросов поиска в кластере, настройте search.default_search_timeout, используя API настроек кластера. Это глобальное значение таймаута используется, если аргумент timeout не передан в запросе. Если глобальный таймаут поиска истечёт до завершения запроса, запрос будет отменён с использованием отмены задач. Параметр search.default_search_timeout по умолчанию равен -1 (без таймаута).

Отмена поиска

Вы можете отменить запрос поиска, используя API управления задачами. Elasticsearch также автоматически отменяет запрос поиска при закрытии HTTP-соединения клиента. Рекомендуется настроить клиента на закрытие HTTP-соединений при прерывании или истечении таймаута запроса поиска.

Отслеживание общего количества хитов

В целом, общее количество хитов нельзя точно вычислить без посещения всех совпадений, что дорого для запросов, которые соответствуют множеству документов. Параметр track_total_hits позволяет управлять тем, как должно отслеживаться общее количество хитов. Учитывая, что часто достаточно иметь нижнюю границу количества хитов, например, «есть как минимум 10000 хитов», значение по умолчанию установлено в 10,000. Это означает, что запросы будут точно считать общее количество хитов до 10,000 хитов. Это хороший баланс между скоростью поиска и точностью количества хитов после определённого порога.

При значении true ответ поиска всегда будет точно отслеживать количество хитов, соответствующих запросу (например, total.relation всегда будет равно "eq", когда track_total_hits установлено в true). В противном случае значение "total.relation", возвращённое в объекте "total" в ответе поиска, определяет, как следует интерпретировать "total.value". Значение "gte" означает, что "total.value" является нижней границей общего количества хитов, соответствующих запросу, а значение "eq" указывает на то, что "total.value" является точным значением.

resp = client.search(
    index="my-index-000001",
    track_total_hits=True,
    query={
        "match": {
            "user.id": "elkbee"
        }
    },
)
print(resp)
response = client.search(
  index: 'my-index-000001',
  body: {
    track_total_hits: true,
    query: {
      match: {
        'user.id' => 'elkbee'
      }
    }
  }
)
puts response
const response = await client.search({
  index: "my-index-000001",
  track_total_hits: true,
  query: {
    match: {
      "user.id": "elkbee",
    },
  },
});
console.log(response);
GET my-index-000001/_search
{
  "track_total_hits": true,
  "query": {
    "match" : {
      "user.id" : "elkbee"
    }
  }
}

… возвращает:

{
  "_shards": ...
  "timed_out": false,
  "took": 100,
  "hits": {
    "max_score": 1.0,
    "total" : {
      "value": 2048,    
      "relation": "eq"  
    },
    "hits": ...
  }
}

Общее количество совпадений с запросом.

Значение подсчёта является точным (например, "eq" означает равенство).

Также можно установить track_total_hits в целое число. Например, следующий запрос будет точно отслеживать общее количество совпадений с запросом до 100 документов:

resp = client.search(
    index="my-index-000001",
    track_total_hits=100,
    query={
        "match": {
            "user.id": "elkbee"
        }
    },
)
print(resp)
response = client.search(
  index: 'my-index-000001',
  body: {
    track_total_hits: 100,
    query: {
      match: {
        'user.id' => 'elkbee'
      }
    }
  }
)
puts response
const response = await client.search({
  index: "my-index-000001",
  track_total_hits: 100,
  query: {
    match: {
      "user.id": "elkbee",
    },
  },
});
console.log(response);
GET my-index-000001/_search
{
  "track_total_hits": 100,
  "query": {
    "match": {
      "user.id": "elkbee"
    }
  }
}

Значение hits.total.relation в ответе укажет, является ли значение, возвращённое в hits.total.value, точным ("eq") или нижней границей общего количества ("gte").

Например, следующий ответ:

{
  "_shards": ...
  "timed_out": false,
  "took": 30,
  "hits": {
    "max_score": 1.0,
    "total": {
      "value": 42,         
      "relation": "eq"     
    },
    "hits": ...
  }
}

42 документа соответствуют запросу

и подсчёт точен ("eq")

… указывает, что количество совпадений, возвращённых в total, является точным.

Если общее количество совпадений с запросом больше значения, установленного в track_total_hits, общее количество совпадений в ответе укажет, что возвращённое значение является нижней границей:

{
  "_shards": ...
  "hits": {
    "max_score": 1.0,
    "total": {
      "value": 100,         
      "relation": "gte"     
    },
    "hits": ...
  }
}

По меньшей мере, 100 документов соответствуют запросу

Это нижняя граница ("gte").

Если вам не нужно отслеживать общее количество совпадений, вы можете улучшить время выполнения запроса, установив этот параметр в false:

resp = client.search(
    index="my-index-000001",
    track_total_hits=False,
    query={
        "match": {
            "user.id": "elkbee"
        }
    },
)
print(resp)
response = client.search(
  index: 'my-index-000001',
  body: {
    track_total_hits: false,
    query: {
      match: {
        'user.id' => 'elkbee'
      }
    }
  }
)
puts response
const response = await client.search({
  index: "my-index-000001",
  track_total_hits: false,
  query: {
    match: {
      "user.id": "elkbee",
    },
  },
});
console.log(response);
GET my-index-000001/_search
{
  "track_total_hits": false,
  "query": {
    "match": {
      "user.id": "elkbee"
    }
  }
}

… возвращает:

{
  "_shards": ...
  "timed_out": false,
  "took": 10,
  "hits": {             
    "max_score": 1.0,
    "hits": ...
  }
}

Общее количество совпадений неизвестно.

Наконец, вы можете принудительно установить точный подсчёт, установив "track_total_hits" в true в запросе.

Параметр track_total_hits позволяет вам обменять точность подсчёта совпадений на производительность. Как правило, чем меньше значение track_total_hits, тем быстрее будет запрос, при этом false возвращает самые быстрые результаты. Установка track_total_hits в значение true заставит Elasticsearch возвращать точные значения количества совпадений, что может негативно сказаться на производительности запросов, поскольку это отключает оптимизацию Max WAND.

Быстрая проверка документов, соответствующих запросу

Если вам нужно только узнать, существуют ли документы, соответствующие определённому запросу, вы можете установить size в значение 0, чтобы указать, что нас не интересуют результаты поиска. Также можно установить terminate_after в значение 1, чтобы указать, что выполнение запроса может быть прервано, как только будет найден первый соответствующий документ (на шред).

resp = client.search(
    q="user.id:elkbee",
    size="0",
    terminate_after="1",
)
print(resp)
response = client.search(
  q: 'user.id:elkbee',
  size: 0,
  terminate_after: 1
)
puts response
const response = await client.search({
  q: "user.id:elkbee",
  size: 0,
  terminate_after: 1,
});
console.log(response);
GET /_search?q=user.id:elkbee&size=0&terminate_after=1

terminate_after всегда применяется после post_filter и останавливает выполнение запроса, а также вычисление агрегаций, когда на шреде будет собрано достаточно совпадений. Хотя количество документов в агрегациях может не отражать hits.total в ответе, поскольку агрегации применяются до фильтрации после запроса.

Ответ не будет содержать никаких совпадений, так как size было установлено в значение 0. hits.total будет либо равно 0, что указывает на отсутствие соответствующих документов, или больше 0, что означает, что было по крайней мере столько же документов, соответствующих запросу, когда запрос был преждевременно прерван. Также, если запрос был прерван преждевременно, флаг terminated_early будет установлен в true в ответе. Некоторые запросы способны получать количество совпадений непосредственно из статистики индекса, что намного быстрее, так как не требует выполнения запроса. В таких ситуациях документы не собираются, возвращаемое значение total.hits будет выше terminate_after, и terminated_early будет установлено в false.

{
  "took": 3,
  "timed_out": false,
  "terminated_early": true,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped" : 0,
    "failed": 0
  },
  "hits": {
    "total" : {
        "value": 1,
        "relation": "eq"
    },
    "max_score": null,
    "hits": []
  }
}

Время took в ответе содержит миллисекунды, затраченные на обработку этого запроса, начиная с момента, когда узел получил запрос, до момента, когда вся работа, связанная с поиском, завершена, и до того, как вышеупомянутый JSON возвращается клиенту. Это означает, что оно включает время ожидания в потоковых пулах, выполнение распределённого поиска по всему кластеру и сборку всех результатов.

© 2023-2025 Elasticsearch
As of September 2024, Elasticsearch is available under a choice of three licenses: the Server Side Public License (SSPL), the Elastic License, or the AGPLv3 (OSI approved).
Elasticsearch and the Elasticsearch logo are trademarks of Elasticsearch B.V., registered in the U.S. and in other countries.
https://www.elastic.co/guide/en/elasticsearch/reference/8.17/search-your-data.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API