Поиск по кластерам
Поиск по нескольким кластерам позволяет выполнить один запрос на поиск по одному или нескольким удалённым кластерам. Например, можно использовать поиск по нескольким кластерам для фильтрации и анализа данных журналов, хранящихся в кластерах разных центров обработки данных.
Поддерживаемые API
Следующие API поддерживают поиск по нескольким кластерам:
- Поиск
- Асинхронный поиск
- Многократный поиск
- Шаблоны поиска
- Шаблоны многократного поиска
- Возможности полей
- Painless execute API
- API разрешения индекса
- [preview] Данная функциональность находится в техническом предварительном просмотре и может быть изменена или удалена в будущих выпусках. Elastic будет работать над устранением проблем, но функции в техническом предварительном просмотре не подпадают под SLA поддержки официальных функций GA. Поиск EQL
- [preview] Данная функциональность находится в техническом предварительном просмотре и может быть изменена или удалена в будущих выпусках. Elastic будет работать над устранением проблем, но функции в техническом предварительном просмотре не подпадают под SLA поддержки официальных функций GA. Поиск SQL
- [preview] Данная функциональность находится в техническом предварительном просмотре и может быть изменена или удалена в будущих выпусках. Elastic будет работать над устранением проблем, но функции в техническом предварительном просмотре не подпадают под SLA поддержки официальных функций GA. Поиск векторных тайлов
- [preview] Данная функциональность находится в техническом предварительном просмотре и может быть изменена или удалена в будущих выпусках. Elastic будет работать над устранением проблем, но функции в техническом предварительном просмотре не подпадают под SLA поддержки официальных функций GA. ES|QL
Предварительные условия
-
Для поиска по нескольким кластерам требуются удаленные кластеры. Чтобы настроить удаленные кластеры в Elasticsearch Service, см. настройку удаленных кластеров в Elasticsearch Service. Если вы используете Elasticsearch на собственном оборудовании, см. Удаленные кластеры.
Чтобы убедиться, что конфигурация вашего удалённого кластера поддерживает поиск по нескольким кластерам, см. Поддерживаемые конфигурации поиска по нескольким кластерам.
- Для полной функциональности поиска по нескольким кластерам локальный и удалённый кластеры должны находиться на одном уровне подписки.
- Координационный узел должен иметь роль узла
remote_cluster_client.
-
Если используется режим sniff, локальный координационный узел должен иметь возможность подключиться к узлам seed и gateway удаленного кластера.
Рекомендуется использовать узлы gateway, способные выступать в качестве координационных узлов. Узлы seed могут быть подмножеством этих узлов gateway.
- Если используется режим прокси, локальный координационный узел должен иметь возможность подключиться к конфигурированному
proxy_address. Прокси по этому адресу должен иметь возможность перенаправлять подключения к узлам gateway и координации на удалённом кластере. - Поиск по нескольким кластерам требует различных разрешений безопасности на локальном и удалённом кластерах. См. Настройка разрешений для поиска по нескольким кластерам и Удаленные кластеры.
Примеры поиска по нескольким кластерам
Настройка удаленного кластера
Следующий запрос API обновления настроек кластера добавляет три удалённых кластера: cluster_one, cluster_two и cluster_three.
resp = client.cluster.put_settings(
persistent={
"cluster": {
"remote": {
"cluster_one": {
"seeds": [
"35.238.149.1:9300"
],
"skip_unavailable": True
},
"cluster_two": {
"seeds": [
"35.238.149.2:9300"
],
"skip_unavailable": False
},
"cluster_three": {
"seeds": [
"35.238.149.3:9300"
]
}
}
}
},
)
print(resp) response = client.cluster.put_settings(
body: {
persistent: {
cluster: {
remote: {
cluster_one: {
seeds: [
'35.238.149.1:9300'
],
skip_unavailable: true
},
cluster_two: {
seeds: [
'35.238.149.2:9300'
],
skip_unavailable: false
},
cluster_three: {
seeds: [
'35.238.149.3:9300'
]
}
}
}
}
}
)
puts response const response = await client.cluster.putSettings({
persistent: {
cluster: {
remote: {
cluster_one: {
seeds: ["35.238.149.1:9300"],
skip_unavailable: true,
},
cluster_two: {
seeds: ["35.238.149.2:9300"],
skip_unavailable: false,
},
cluster_three: {
seeds: ["35.238.149.3:9300"],
},
},
},
},
});
console.log(response); PUT _cluster/settings
{
"persistent": {
"cluster": {
"remote": {
"cluster_one": {
"seeds": [
"35.238.149.1:9300"
],
"skip_unavailable": true
},
"cluster_two": {
"seeds": [
"35.238.149.2:9300"
],
"skip_unavailable": false
},
"cluster_three": {
"seeds": [
"35.238.149.3:9300"
]
}
}
}
}
} | Так как |
Поиск в одном удалённом кластере
В запросе на поиск вы указываете потоки данных и индексы на удалённом кластере как <remote_cluster_name>:<target>.
Следующий запрос API поиска ищет в индексе my-index-000001 на одном удалённом кластере cluster_one.
resp = client.search(
index="cluster_one:my-index-000001",
size=1,
query={
"match": {
"user.id": "kimchy"
}
},
source=[
"user.id",
"message",
"http.response.status_code"
],
)
print(resp) response = client.search(
index: 'cluster_one:my-index-000001',
body: {
size: 1,
query: {
match: {
'user.id' => 'kimchy'
}
},
_source: [
'user.id',
'message',
'http.response.status_code'
]
}
)
puts response const response = await client.search({
index: "cluster_one:my-index-000001",
size: 1,
query: {
match: {
"user.id": "kimchy",
},
},
_source: ["user.id", "message", "http.response.status_code"],
});
console.log(response); GET /cluster_one:my-index-000001/_search
{
"size": 1,
"query": {
"match": {
"user.id": "kimchy"
}
},
"_source": ["user.id", "message", "http.response.status_code"]
} API возвращает следующий ответ. Обратите внимание, что при поиске в одном или нескольких удалённых кластерах включён раздел _clusters, предоставляющий информацию о поиске в каждом кластере.
{
"took": 150,
"timed_out": false,
"_shards": {
"total": 12,
"successful": 12,
"failed": 0,
"skipped": 0
},
"_clusters": {
"total": 1,
"successful": 1,
"skipped": 0,
"running": 0,
"partial": 0,
"failed": 0,
"details": {
"cluster_one": {
"status": "successful",
"indices": "my-index-000001",
"took": 148,
"timed_out": false,
"_shards": {
"total": 12,
"successful": 12,
"skipped": 0,
"failed": 0
}
}
}
},
"hits": {
"total" : {
"value": 1,
"relation": "eq"
},
"max_score": 1,
"hits": [
{
"_index": "cluster_one:my-index-000001",
"_id": "0",
"_score": 1,
"_source": {
"user": {
"id": "kimchy"
},
"message": "GET /search HTTP/1.1 200 1070000",
"http": {
"response":
{
"status_code": 200
}
}
}
}
]
}
} | Этот раздел счётчиков отображает все возможные состояния поиска по кластеру и количество текущих поисков в каждом из этих состояний. Кластеры могут быть в следующих состояниях: running, successful (поиск на всех фрагментах был успешным), partial (поиск на хотя бы одном фрагменте кластера был успешным, а на одном — нет), skipped (поиск по кластеру завершился ошибкой, так как он помечен как | |
| Раздел | |
| Выражение индекса, предоставленное пользователем. Если вы используете подстановку, например, | |
| Время выполнения подпоиска на данном кластере (в миллисекундах). | |
| Подробности о фрагментах для подпоиска на данном кластере. | |
| Ответ API поиска содержит имя удалённого кластера в параметре |
Поиск по нескольким удалённым кластерам
Следующий запрос API поиска ищет в индексе my-index-000001 по трём кластерам:
- Локальный ("запрашивающий") кластер с 10 фрагментами
- Два удалённых кластера,
cluster_oneс 12 фрагментами иcluster_twoс 6 фрагментами.
resp = client.search(
index="my-index-000001,cluster_one:my-index-000001,cluster_two:my-index-000001",
query={
"match": {
"user.id": "kimchy"
}
},
source=[
"user.id",
"message",
"http.response.status_code"
],
)
print(resp) response = client.search(
index: 'my-index-000001,cluster_one:my-index-000001,cluster_two:my-index-000001',
body: {
query: {
match: {
'user.id' => 'kimchy'
}
},
_source: [
'user.id',
'message',
'http.response.status_code'
]
}
)
puts response const response = await client.search({
index:
"my-index-000001,cluster_one:my-index-000001,cluster_two:my-index-000001",
query: {
match: {
"user.id": "kimchy",
},
},
_source: ["user.id", "message", "http.response.status_code"],
});
console.log(response); GET /my-index-000001,cluster_one:my-index-000001,cluster_two:my-index-000001/_search
{
"query": {
"match": {
"user.id": "kimchy"
}
},
"_source": ["user.id", "message", "http.response.status_code"]
} API возвращает следующий ответ:
{
"took": 150,
"timed_out": false,
"num_reduce_phases": 4,
"_shards": {
"total": 28,
"successful": 28,
"failed": 0,
"skipped": 0
},
"_clusters": {
"total": 3,
"successful": 3,
"skipped": 0,
"running": 0,
"partial": 0,
"failed": 0,
"details": {
"(local)": {
"status": "successful",
"indices": "my-index-000001",
"took": 21,
"timed_out": false,
"_shards": {
"total": 10,
"successful": 10,
"skipped": 0,
"failed": 0
}
},
"cluster_one": {
"status": "successful",
"indices": "my-index-000001",
"took": 48,
"timed_out": false,
"_shards": {
"total": 12,
"successful": 12,
"skipped": 0,
"failed": 0
}
},
"cluster_two": {
"status": "successful",
"indices": "my-index-000001",
"took": 141,
"timed_out": false,
"_shards": {
"total" : 6,
"successful" : 6,
"skipped": 0,
"failed": 0
}
}
}
},
"hits": {
"total" : {
"value": 3,
"relation": "eq"
},
"max_score": 1,
"hits": [
{
"_index": "my-index-000001",
"_id": "0",
"_score": 2,
"_source": {
"user": {
"id": "kimchy"
},
"message": "GET /search HTTP/1.1 200 1070000",
"http": {
"response":
{
"status_code": 200
}
}
}
},
{
"_index": "cluster_one:my-index-000001",
"_id": "0",
"_score": 1,
"_source": {
"user": {
"id": "kimchy"
},
"message": "GET /search HTTP/1.1 200 1070000",
"http": {
"response":
{
"status_code": 200
}
}
}
},
{
"_index": "cluster_two:my-index-000001",
"_id": "0",
"_score": 1,
"_source": {
"user": {
"id": "kimchy"
},
"message": "GET /search HTTP/1.1 200 1070000",
"http": {
"response":
{
"status_code": 200
}
}
}
}
]
}
} | Локальный (запрашивающий) кластер идентифицируется как "(local)". | |
| Параметр | |
| Этот документ пришел из | |
| Этот документ пришел из |
Использование асинхронного поиска для межкластерного поиска с ccs_minimize_roundtrips=true
Удаленные кластеры могут быть запрошены асинхронно с помощью API асинхронного поиска. Межкластерный поиск принимает параметр ccs_minimize_roundtrips. Для асинхронных поисков он по умолчанию равен false. (Примечание: для синхронных поисков он по умолчанию равен true.) См. Рекомендации по выбору минимизации обменов данными при межкластерном поиске, чтобы узнать больше об этом параметре.
Следующий запрос выполняет асинхронный поиск индекса my-index-000001 с использованием ccs_minimize_roundtrips=true в трех кластерах (таких же, как в предыдущем примере).
resp = client.async_search.submit(
index="my-index-000001,cluster_one:my-index-000001,cluster_two:my-index-000001",
ccs_minimize_roundtrips=True,
query={
"match": {
"user.id": "kimchy"
}
},
source=[
"user.id",
"message",
"http.response.status_code"
],
)
print(resp) response = client.async_search.submit(
index: 'my-index-000001,cluster_one:my-index-000001,cluster_two:my-index-000001',
ccs_minimize_roundtrips: true,
body: {
query: {
match: {
'user.id' => 'kimchy'
}
},
_source: [
'user.id',
'message',
'http.response.status_code'
]
}
)
puts response const response = await client.asyncSearch.submit({
index:
"my-index-000001,cluster_one:my-index-000001,cluster_two:my-index-000001",
ccs_minimize_roundtrips: "true",
query: {
match: {
"user.id": "kimchy",
},
},
_source: ["user.id", "message", "http.response.status_code"],
});
console.log(response); POST /my-index-000001,cluster_one:my-index-000001,cluster_two:my-index-000001/_async_search?ccs_minimize_roundtrips=true
{
"query": {
"match": {
"user.id": "kimchy"
}
},
"_source": ["user.id", "message", "http.response.status_code"]
} API возвращает следующий ответ:
{
"id": "FklQYndoTDJ2VEFlMEVBTzFJMGhJVFEaLVlKYndBWWZSMUdicUc4WVlEaFl4ZzoxNTU=",
"is_partial": true,
"is_running": true,
"start_time_in_millis": 1685563581380,
"expiration_time_in_millis": 1685995581380,
"response": {
"took": 1020,
"timed_out": false,
"num_reduce_phases": 0,
"_shards": {
"total": 10,
"successful": 0,
"failed": 0,
"skipped": 0
},
"_clusters": {
"total" : 3,
"successful" : 0,
"skipped": 0,
"running": 3,
"partial": 0,
"failed": 0,
"details": {
"(local)": {
"status": "running",
"indices": "my-index-000001",
"timed_out": false
},
"cluster_one": {
"status": "running",
"indices": "my-index-000001",
"timed_out": false
},
"cluster_one": {
"status": "running",
"indices": "my-index-000001",
"timed_out": false
}
}
},
"hits": {
"total" : {
"value": 0,
"relation": "eq"
},
"max_score": null,
"hits": []
}
}
} | Идентификатор асинхронного поиска. | |
| Когда | |
| Раздел |
Если вы запросите конечную точку получения асинхронного поиска, в то время как запрос всё ещё выполняется, вы увидите обновление в разделе _clusters и _shards ответа по мере завершения поиска каждым кластером.
Если вы установите ccs_minimize_roundtrips=false, то также увидите частичные результаты агрегации из фрагментов (из любого кластера), которые завершились, но результаты в разделе "hits" не будут показаны, пока поиск не завершится.
Если вы установите ccs_minimize_roundtrips=true, то также увидите частичные результаты в секциях "hits" и "aggregations" ответа от всех кластеров, которые завершили поиск до сих пор. (Примечание: частичные результаты агрегации от локального кластера могут быть видны даже до его завершения.) Пример ниже демонстрирует случай ccs_minimize_roundtrips=true.
resp = client.async_search.get(
id="FklQYndoTDJ2VEFlMEVBTzFJMGhJVFEaLVlKYndBWWZSMUdicUc4WVlEaFl4ZzoxNTU=",
)
print(resp) response = client.async_search.get( id: 'FklQYndoTDJ2VEFlMEVBTzFJMGhJVFEaLVlKYndBWWZSMUdicUc4WVlEaFl4ZzoxNTU=' ) puts response
const response = await client.asyncSearch.get({
id: "FklQYndoTDJ2VEFlMEVBTzFJMGhJVFEaLVlKYndBWWZSMUdicUc4WVlEaFl4ZzoxNTU=",
});
console.log(response); GET /_async_search/FklQYndoTDJ2VEFlMEVBTzFJMGhJVFEaLVlKYndBWWZSMUdicUc4WVlEaFl4ZzoxNTU=
Ответ:
{
"id": "FklQYndoTDJ2VEFlMEVBTzFJMGhJVFEaLVlKYndBWWZSMUdicUc4WVlEaFl4ZzoxNTU=",
"is_partial": true,
"is_running": true,
"start_time_in_millis": 1685564911108,
"expiration_time_in_millis": 1685996911108,
"response": {
"took": 11164,
"timed_out": false,
"terminated_early": false,
"_shards": {
"total": 22,
"successful": 22,
"skipped": 0,
"failed": 0
},
"_clusters": {
"total": 3,
"successful": 2,
"skipped": 0,
"running": 1,
"partial": 0,
"failed": 0,
"details": {
"(local)": {
"status": "successful",
"indices": "my-index-000001",
"took": 2034,
"timed_out": false,
"_shards": {
"total": 10,
"successful": 10,
"skipped": 0,
"failed": 0
}
},
"cluster_one": {
"status": "successful",
"indices": "my-index-000001",
"took": 9039,
"timed_out": false,
"_shards": {
"total": 12,
"successful": 12,
"skipped": 0,
"failed": 0
}
},
"cluster_two": {
"status": "running",
"indices": "my-index-000001",
"timed_out": false
}
}
},
"hits": {
"total": {
"value": 542,
"relation": "eq"
},
"max_score": 1.7232,
"hits": [...list of hits here...]
}
}
} | Поиски по всем фрагментам локального кластера и удалённого кластера | |
| Поскольку два кластера завершили поиск, запись "successful" кластеров установлена в 2, а запись "running" кластеров уменьшена до 1. Метаданные ответа | |
| Количество совпадений (hits) из завершённых поисков до сих пор. Окончательные совпадения не отображаются до завершения и объединения поисков по всем кластерам. Таким образом, раздел "hits" может меняться по мере запроса этой конечной точки до тех пор, пока поиск полностью не завершится. |
После завершения поисков по всем кластерам, запрос конечной точки получения асинхронного поиска покажет окончательный статус раздела _clusters и _shards, а также совпадения (hits) и результаты любых агрегаций.
resp = client.async_search.get(
id="FklQYndoTDJ2VEFlMEVBTzFJMGhJVFEaLVlKYndBWWZSMUdicUc4WVlEaFl4ZzoxNTU=",
)
print(resp) response = client.async_search.get( id: 'FklQYndoTDJ2VEFlMEVBTzFJMGhJVFEaLVlKYndBWWZSMUdicUc4WVlEaFl4ZzoxNTU=' ) puts response
const response = await client.asyncSearch.get({
id: "FklQYndoTDJ2VEFlMEVBTzFJMGhJVFEaLVlKYndBWWZSMUdicUc4WVlEaFl4ZzoxNTU=",
});
console.log(response); GET /_async_search/FklQYndoTDJ2VEFlMEVBTzFJMGhJVFEaLVlKYndBWWZSMUdicUc4WVlEaFl4ZzoxNTU=
Ответ:
{
"id": "FklQYndoTDJ2VEFlMEVBTzFJMGhJVFEaLVlKYndBWWZSMUdicUc4WVlEaFl4ZzoxNTU=",
"is_partial": false,
"is_running": false,
"start_time_in_millis": 1685564911108,
"expiration_time_in_millis": 1685996911108,
"completion_time_in_millis": 1685564938727,
"response": {
"took": 27619,
"timed_out": false,
"num_reduce_phases": 4,
"_shards": {
"total": 28,
"successful": 28,
"skipped": 0,
"failed": 0
},
"_clusters": {
"total": 3,
"successful": 3,
"skipped": 0,
"running": 0,
"partial": 0,
"failed": 0,
"details": {
"(local)": {
"status": "successful",
"indices": "my-index-000001",
"took": 2034,
"timed_out": false,
"_shards": {
"total": 10,
"successful": 10,
"skipped": 0,
"failed": 0
}
},
"cluster_one": {
"status": "successful",
"indices": "my-index-000001",
"took": 9039,
"timed_out": false,
"_shards": {
"total": 12,
"successful": 12,
"skipped": 0,
"failed": 0
}
},
"cluster_two": {
"status": "successful",
"indices": "my-index-000001",
"took": 27550,
"timed_out": false,
"_shards": {
"total": 6,
"successful": 6,
"skipped": 0,
"failed": 0
}
}
}
},
"hits": {
"total": {
"value": 1067,
"relation": "eq"
},
"max_score": 1.8293576,
"hits": [...list of hits here...]
}
}
} | После завершения поиска присутствует поле completion_time. | |
| Теперь раздел | |
| Раздел |
Ошибки межкластерного поиска
Ошибки во время межкластерного поиска могут привести к одному из двух состояний:
- частичные результаты (HTTP-код состояния 2xx)
- ошибка поиска (HTTP-код состояния 4xx или 5xx)
Подробная информация об ошибках будет присутствовать в ответе поиска в обоих случаях.
Поиск будет считаться ошибочным, если кластер, отмеченный skip_unavailable=false, недоступен, отключается во время поиска или имеет ошибки поиска на всех фрагментах. Во всех остальных случаях ошибки приведут к частичным результатам.
Сведения об ошибках поиска на отдельных фрагментах будут присутствовать как в разделе _shards, так и в разделе _clusters ответа.
При ошибочном поиске в ответе будет присутствовать дополнительная запись верхнего уровня errors.
Вот пример поиска с частичными результатами из-за ошибки на одном фрагменте одного кластера. Поиск будет аналогичен предыдущим. Здесь используется конечная точка _async_search/status, чтобы показать статус завершения и не показывать совпадения (hits).
resp = client.async_search.status(
id="FmpwbThueVB4UkRDeUxqb1l4akIza3cbWEJyeVBPQldTV3FGZGdIeUVabXBldzoyMDIw",
)
print(resp) response = client.async_search.status( id: 'FmpwbThueVB4UkRDeUxqb1l4akIza3cbWEJyeVBPQldTV3FGZGdIeUVabXBldzoyMDIw' ) puts response
const response = await client.asyncSearch.status({
id: "FmpwbThueVB4UkRDeUxqb1l4akIza3cbWEJyeVBPQldTV3FGZGdIeUVabXBldzoyMDIw",
});
console.log(response); GET /_async_search/status/FmpwbThueVB4UkRDeUxqb1l4akIza3cbWEJyeVBPQldTV3FGZGdIeUVabXBldzoyMDIw
Ответ:
{
"id": "FmpwbThueVB4UkRDeUxqb1l4akIza3cbWEJyeVBPQldTV3FGZGdIeUVabXBldzoyMDIw",
"is_partial": true,
"is_running": false,
"start_time_in_millis": 1692106901478,
"expiration_time_in_millis": 1692538901478,
"completion_time_in_millis": 1692106903547,
"response": {
"took": 2069,
"timed_out": false,
"num_reduce_phases": 4,
"_shards": {
"total": 28,
"successful": 27,
"skipped": 0,
"failed": 1,
"failures": [
{
"shard": 1,
"index": "cluster_two:my-index-000001",
"node": "LMpUnAu0QEeCUMfg_56sAg",
"reason": {
"type": "query_shard_exception",
"reason": "failed to create query: [my-index-000001][1] exception message here",
"index_uuid": "4F2VWx8RQSeIhUE-nksvCQ",
"index": "cluster_two:my-index-000001",
"caused_by": {
"type": "runtime_exception",
"reason": "runtime_exception: [my-index-000001][1] exception message here"
}
}
}
]
},
"_clusters": {
"total": 3,
"successful": 2,
"skipped": 0,
"running": 0,
"partial": 1,
"failed": 0,
"details": {
"(local)": {
"status": "successful",
"indices": "my-index-000001",
"took": 1753,
"timed_out": false,
"_shards": {
"total": 10,
"successful": 10,
"skipped": 0,
"failed": 0
}
},
"cluster_one": {
"status": "successful",
"indices": "my-index-000001",
"took": 2054,
"timed_out": false,
"_shards": {
"total": 12,
"successful": 12,
"skipped": 0,
"failed": 0
}
},
"cluster_two": {
"status": "partial",
"indices": "my-index-000001",
"took": 2039,
"timed_out": false,
"_shards": {
"total": 6,
"successful": 5,
"skipped": 0,
"failed": 1
},
"failures": [
{
"shard": 1,
"index": "cluster_two:my-index-000001",
"node": "LMpUnAu0QEeCUMfg_56sAg",
"reason": {
"type": "query_shard_exception",
"reason": "failed to create query: [my-index-000001][1] exception message here",
"index_uuid": "4F2VWx8RQSeIhUE-nksvCQ",
"index": "cluster_two:my-index-000001",
"caused_by": {
"type": "runtime_exception",
"reason": "runtime_exception: [my-index-000001][1] exception message here"
}
}
}
]
}
}
},
"hits": {
}
}
} | Результаты поиска помечены как частичные, так как по крайней мере один поиск фрагмента завершился ошибкой. | |
| Раздел | |
| Кластеры с частичными результатами по-прежнему помечены как "частичные". Они отмечаются статусом "skipped" (или "failed") только в том случае, если из поиска не возвращались данные. | |
| Статус | |
| Показано количество фрагментов с ошибками. | |
| Ошибки фрагментов также перечислены в записи кластера/подробности. |
Вот пример, где cluster_one и cluster_two потеряли соединение во время межкластерного поиска. Так как cluster_one помечен как skip_unavailable=true, его статус — skipped, а так как cluster_two помечен как skip_unavailable=false, его статус — failed. Поскольку был кластер failed, также присутствует запись верхнего уровня error, которая возвращает HTTP-статус 500 (не показано).
Если вы хотите, чтобы поиск всё ещё возвращал результаты, даже если кластер недоступен, установите skip_unavailable=true для всех удалённых кластеров.
resp = client.async_search.get(
id="FjktRGJ1Y2w1U0phLTRhZnVyeUZ2MVEbWEJyeVBPQldTV3FGZGdIeUVabXBldzo5NzA4",
)
print(resp) response = client.async_search.get( id: 'FjktRGJ1Y2w1U0phLTRhZnVyeUZ2MVEbWEJyeVBPQldTV3FGZGdIeUVabXBldzo5NzA4' ) puts response
const response = await client.asyncSearch.get({
id: "FjktRGJ1Y2w1U0phLTRhZnVyeUZ2MVEbWEJyeVBPQldTV3FGZGdIeUVabXBldzo5NzA4",
});
console.log(response); GET /_async_search/FjktRGJ1Y2w1U0phLTRhZnVyeUZ2MVEbWEJyeVBPQldTV3FGZGdIeUVabXBldzo5NzA4
Ответ:
{
"id": "FjktRGJ1Y2w1U0phLTRhZnVyeUZ2MVEbWEJyeVBPQldTV3FGZGdIeUVabXBldzo5NzA4",
"is_partial": true,
"is_running": false,
"start_time_in_millis": 1692112102650,
"expiration_time_in_millis": 1692544102650,
"completion_time_in_millis": 1692112106177,
"response": {
"took": 3527,
"timed_out": false,
"terminated_early": false,
"_shards": {
"total": 10,
"successful": 10,
"skipped": 0,
"failed": 0
},
"_clusters": {
"total": 3,
"successful": 1,
"skipped": 1,
"running": 0,
"partial": 0,
"failed": 1,
"details": {
"(local)": {
"status": "successful",
"indices": "my-index-000001",
"took": 1473,
"timed_out": false,
"_shards": {
"total": 10,
"successful": 10,
"skipped": 0,
"failed": 0
}
},
"cluster_one": {
"status": "skipped",
"indices": "my-index-000001",
"timed_out": false,
"failures": [
{
"shard": -1,
"index": null,
"reason": {
"type": "node_disconnected_exception",
"reason": "[myhostname1][35.238.149.1:9300][indices:data/read/search] disconnected"
}
}
]
},
"cluster_two": {
"status": "failed",
"indices": "my-index-000001",
"timed_out": false,
"failures": [
{
"shard": -1,
"index": null,
"reason": {
"type": "node_disconnected_exception",
"reason": "[myhostname2][35.238.149.2:9300][indices:data/read/search] disconnected"
}
}
]
}
}
},
"hits": {
},
}
"error": {
"type": "status_exception",
"reason": "error while executing search",
"caused_by": {
"type": "node_disconnected_exception",
"reason": "[myhostname2][35.238.149.2:9300][indices:data/read/search] disconnected"
}
}
} | Учёт фрагментов часто будет неполным при возникновении таких ошибок, так как нам необходимо получать информацию о фрагментах из удалённых кластеров при каждом поиске. | |
|
| |
| Список ошибок показывает, что узел удалённого кластера отключился от запросившего кластера. | |
| Состояние | |
| Запись верхнего уровня |
Исключение кластеров или индексов из межкластерного поиска
Если вы используете подстановку для включения большого списка кластеров и/или индексов, вы можете явно исключить один или несколько кластеров или индексов, поставив перед кластером или индексом знак - минус.
Чтобы исключить весь кластер, вы должны поставить знак минус перед псевдонимом кластера, например: -mycluster:*. При исключении кластера необходимо использовать * в позиции индекса, иначе будет возвращена ошибка.
Чтобы исключить конкретный удалённый индекс, вы должны поставить знак минус перед индексом, например mycluster:-myindex.
Исключение удалённого кластера
Вот как вы бы исключили cluster_three из межкластерного поиска, использующего подстановку для указания списка кластеров:
resp = client.async_search.submit(
index="my-index-000001,cluster*:my-index-000001,-cluster_three:*",
query={
"match": {
"user.id": "kimchy"
}
},
source=[
"user.id",
"message",
"http.response.status_code"
],
)
print(resp) const response = await client.asyncSearch.submit({
index: "my-index-000001,cluster*:my-index-000001,-cluster_three:*",
query: {
match: {
"user.id": "kimchy",
},
},
_source: ["user.id", "message", "http.response.status_code"],
});
console.log(response); POST /my-index-000001,cluster*:my-index-000001,-cluster_three:*/_async_search
{
"query": {
"match": {
"user.id": "kimchy"
}
},
"_source": ["user.id", "message", "http.response.status_code"]
} | Обозначение |
Исключение удалённого индекса
Предположим, вы хотите искать все индексы, соответствующие my-index-*, но хотите исключить my-index-000001 на cluster_three. Вот как можно это сделать:
resp = client.async_search.submit(
index="my-index-000001,cluster*:my-index-*,cluster_three:-my-index-000001",
query={
"match": {
"user.id": "kimchy"
}
},
source=[
"user.id",
"message",
"http.response.status_code"
],
)
print(resp) const response = await client.asyncSearch.submit({
index: "my-index-000001,cluster*:my-index-*,cluster_three:-my-index-000001",
query: {
match: {
"user.id": "kimchy",
},
},
_source: ["user.id", "message", "http.response.status_code"],
});
console.log(response); POST /my-index-000001,cluster*:my-index-*,cluster_three:-my-index-000001/_async_search
{
"query": {
"match": {
"user.id": "kimchy"
}
},
"_source": ["user.id", "message", "http.response.status_code"]
} | Это не исключит |
Использование асинхронного поиска для межкластерного поиска с ccs_minimize_roundtrips=false
Раздел _shards и _clusters ответа ведут себя по-разному, когда ccs_minimize_roundtrips равно false.
Ключевые различия:
- Суммарное количество в разделе
_shardsбудет точным сразу же, так как общее количество фрагментов собирается со всех кластеров перед началом поиска. - Раздел
_shardsбудет постепенно обновляться по мере завершения поисков на отдельных фрагментах, тогда как при минимизации циклов обмена фрагмент будет обновляться по мере завершения поисков на фрагментах локального кластера, а затем по мере получения каждого удалённого кластера полного результата поиска. - Раздел
_clusterначинает перечислять все счётчики фрагментов, так как они также получаются до начала фазы запроса.
Пример, использующий ту же настройку, что и в предыдущем разделе (ccs_minimize_roundtrips=true):
resp = client.async_search.submit(
index="my-index-000001,cluster_one:my-index-000001,cluster_two:my-index-000001",
ccs_minimize_roundtrips=False,
query={
"match": {
"user.id": "kimchy"
}
},
source=[
"user.id",
"message",
"http.response.status_code"
],
)
print(resp) const response = await client.asyncSearch.submit({
index:
"my-index-000001,cluster_one:my-index-000001,cluster_two:my-index-000001",
ccs_minimize_roundtrips: "false",
query: {
match: {
"user.id": "kimchy",
},
},
_source: ["user.id", "message", "http.response.status_code"],
});
console.log(response); POST /my-index-000001,cluster_one:my-index-000001,cluster_two:my-index-000001/_async_search?ccs_minimize_roundtrips=false
{
"query": {
"match": {
"user.id": "kimchy"
}
},
"_source": ["user.id", "message", "http.response.status_code"]
} API возвращает следующий ответ, если запрос занимает больше времени, чем wait_for_completion_timeout (см. Асинхронный поиск).
{
"id": "FklQYndoTDJ2VEFlMEVBTzFJMGhJVFEaLVlKYndBWWZSMUdicUc4WVlEaFl4ZzoxNTU=",
"is_partial": true,
"is_running": true,
"start_time_in_millis": 1685563581380,
"expiration_time_in_millis": 1685995581380,
"response": {
"took": 1020,
"timed_out": false,
"_shards": {
"total": 28,
"successful": 0,
"failed": 0,
"skipped": 0
},
"_clusters": {
"total" : 3,
"successful": 0,
"skipped": 0,
"running": 3,
"partial": 0,
"failed": 0,
"details": {
"(local)": {
"status": "running",
"indices": "my-index-000001",
"timed_out": false,
"_shards": {
"total": 10,
"successful": 0,
"skipped": 0,
"failed": 0
}
},
"cluster_one": {
"status": "running",
"indices": "my-index-000001",
"timed_out": false,
"_shards": {
"total": 12,
"successful": 0,
"skipped": 0,
"failed": 0
}
},
"cluster_two": {
"status": "running",
"indices": "my-index-000001",
"timed_out": false,
"_shards": {
"total": 6,
"successful": 0,
"skipped": 0,
"failed": 0
}
}
}
},
"hits": {
"total" : {
"value": 0,
"relation": "eq"
},
"max_score": null,
"hits": []
}
}
} | Здесь перечислены все фрагменты со всех кластеров, охватываемых поиском. Следите за этим разделом и/или разделом «_clusters» для отслеживания прогресса поиска. | |
| Из раздела | |
| Раздел |
Необязательные удалённые кластеры
По умолчанию межкластерный поиск завершается ошибкой, если удалённый кластер в запросе недоступен или возвращает ошибку, где поиск по всем фрагментам завершился ошибкой. Используйте настройку кластера skip_unavailable, чтобы пометить определённый удалённый кластер как необязательный или обязательный для межкластерного поиска.
В Elasticsearch 8.15 значение по умолчанию для skip_unavailable было изменено с false на true. До Elasticsearch 8.15, если вы хотите, чтобы кластер рассматривался как необязательный для межкластерного поиска, вам нужно настроить это. С Elasticsearch 8.15 и далее вам нужно установить настройку, чтобы сделать кластер обязательным для межкластерного поиска.
Если skip_unavailable равно true, межкластерный поиск:
- Пропускает удалённый кластер, если его узлы недоступны во время поиска. Значение
_clusters.skippedв ответе содержит количество пропущенных кластеров, а раздел_clusters.detailsответа покажет состояниеskipped. - Игнорирует ошибки, возвращаемые удалённым кластером, такие как ошибки, связанные с недоступными фрагментами или индексами. Это может включать ошибки, связанные с параметрами поиска, такими как
allow_no_indicesиignore_unavailable. - Игнорирует параметр
allow_partial_search_resultsи связанную с ним настройку кластераsearch.default_allow_partial_resultsпри поиске в удалённом кластере. Это означает, что поиски в удалённом кластере могут возвращать частичные результаты.
Вы можете изменить настройку skip_unavailable, отредактировав настройки cluster.remote.<cluster_alias> в файле конфигурации elasticsearch.yml. Например:
cluster:
remote:
cluster_one:
seeds: 35.238.149.1:9300
skip_unavailable: false
cluster_two:
seeds: 35.238.149.2:9300
skip_unavailable: true Или вы можете установить настройки cluster.remote с помощью API обновления настроек кластера, как показано здесь.
Когда удалённый кластер, настроенный с skip_unavailable: true (например, cluster_two выше), отключён или недоступен во время межкластерного поиска, Elasticsearch не будет включать соответствующие документы из этого кластера в окончательные результаты, и поиск будет считаться успешным (HTTP-код ответа 200 OK).
Если хотя бы один фрагмент из кластера предоставляет результаты поиска, эти результаты будут использоваться, и поиск вернёт частичные данные. Это верно независимо от настройки skip_unavailable удалённого кластера. (Если выполняется межкластерный поиск с использованием асинхронного поиска, поле is_partial будет установлено в true, чтобы указать на частичные результаты.)
Как межкластерный поиск обрабатывает задержки сети
Поскольку межкластерный поиск подразумевает отправку запросов в удалённые кластеры, любые задержки сети могут повлиять на скорость поиска. Чтобы избежать медленных поисков, межкластерный поиск предлагает два варианта для обработки задержек сети:
- Минимизация сетевых циклов обмена
-
По умолчанию Elasticsearch уменьшает количество сетевых циклов обмена между удалёнными кластерами. Это снижает влияние сетевых задержек на скорость поиска. Однако Elasticsearch не может уменьшить сетевые циклы обмена для больших запросов поиска, таких как запросы с прокруткой или внутренними результатами.
См. Уменьшение сетевых циклов обмена в межкластерном поиске, чтобы узнать, как работает этот параметр.
- Не минимизировать сетевые циклы обмена
-
Для запросов поиска, включающих прокрутку или внутренние результаты, Elasticsearch отправляет несколько исходящих и входящих запросов каждому удалённому кластеру. Вы также можете выбрать этот вариант, установив параметр
ccs_minimize_roundtripsв значениеfalse. Хотя этот подход обычно медленнее, он может хорошо работать для сетей с низкой задержкой.См. Не минимизировать сетевые циклы обмена, чтобы узнать, как работает этот параметр.
API поиска векторных тайлов всегда минимизирует сетевые циклы обмена и не включает параметр ccs_minimize_roundtrips.
Приближенный поиск kNN не поддерживает минимизацию сетевых циклов обмена и устанавливает параметр ccs_minimize_roundtrips в значение false.
Уменьшение сетевых циклов обмена в межкластерном поиске
Преимущества минимизации циклов обмена:
- Для межкластерных поисков, которые запрашивают большое количество фрагментов, вариант минимизации циклов обмена обычно обеспечивает гораздо лучшую производительность. Это особенно актуально, если кластеры, которые просматриваются, имеют высокую сетевую задержку (например, удалённые географические регионы).
- При асинхронном межкластерном поиске конечная точка
GET _async_search/<search_id>предоставит как лучшие совпадения, так и агрегации со всех кластеров, которые сообщили о результатах, даже при том, что поиск всё ещё выполняется в других кластерах. Другими словами, он предоставляет «инкрементные» частичные результаты по мере продвижения поиска. Обратите внимание, что если локальный кластер включён в поиск, он обрабатывается особым образом, так как может показывать частичные агрегации (но не частичные лучшие совпадения) в то время, когда поиск в локальном кластере всё ещё выполняется.
Отказ от минимизации циклов обмена при использовании асинхронного поиска позволяет получить инкрементные результаты любых агрегаций в запросе по мере завершения отдельных фрагментов (а не целых кластеров), в то время как поиск всё ещё выполняется, но лучшие совпадения не отображаются, пока поиск не завершится во всех кластерах.
По умолчанию синхронные поиски минимизируют циклы обмена, а асинхронные поиски — нет. Вы можете переопределить значение по умолчанию, используя параметр ccs_minimize_roundtrips, установив его в значение true или false, как показано в нескольких примерах ранее в этом документе.
Минимизация сетевых циклов обмена
Вот как работает межкластерный поиск, когда минимизируются сетевые циклы обмена.
-
Вы отправляете запрос межкластерного поиска на локальный кластер. Координирующий узел в этом кластере получает и анализирует запрос.
-
Координирующий узел отправляет один запрос поиска каждому кластеру, включая локальный кластер. Каждый кластер выполняет запрос поиска независимо, применяя к нему свои собственные настройки на уровне кластера.
-
Каждый удалённый кластер отправляет свои результаты поиска обратно координационному узлу.
-
После сбора результатов от каждого кластера координационный узел возвращает окончательные результаты в ответе межкластерного поиска.
Не минимизировать сетевые циклы обмена
Вот как работает межкластерный поиск, когда сетевые циклы обмена не минимизируются.
-
Вы отправляете запрос межкластерного поиска на локальный кластер. Координирующий узел в этом кластере получает и анализирует запрос.
-
Координирующий узел отправляет запрос транспортного уровня «поиск фрагментов» каждому удалённому кластеру, чтобы те выполнили поиск «соответствие» для определения, на каких фрагментах каждого кластера следует выполнять поиск.
-
Каждый удалённый кластер отправляет свой ответ обратно координационному узлу. Этот ответ содержит информацию об индексах и фрагментах, на которых будет выполняться запрос межкластерного поиска.
-
Координирующий узел отправляет запрос поиска каждому фрагменту, включая те, которые находятся в собственном кластере. Каждый фрагмент выполняет запрос поиска независимо.
Когда сетевые циклы обмена не минимизируются, поиск выполняется так, как если бы все данные находились в кластере координационного узла. Мы рекомендуем обновить настройки на уровне кластера, которые ограничивают поиски, такие как
action.search.shard_count.limit,pre_filter_shard_sizeиmax_concurrent_shard_requests, чтобы учесть это. Если эти ограничения слишком низкие, поиск может быть отклонен. -
Каждый фрагмент отправляет свои результаты поиска обратно координационному узлу.
-
После сбора результатов от каждого кластера координационный узел возвращает окончательные результаты в ответе межкластерного поиска.
Поддерживаемые конфигурации межкластерного поиска
В версии 8.0+ Elastic поддерживает поиски с локального кластера на удалённый кластер, работающий:
- На предыдущей младшей версии.
- На той же версии.
- На более новой младшей версии в той же основной версии.
Elastic также поддерживает поиски с локального кластера, работающего на последней младшей версии основной версии, на удалённый кластер, работающий на любой младшей версии следующей основной версии. Например, локальный кластер версии 7.17 может выполнять поиск на любом удалённом кластере версии 8.x.
Версия удалённого кластера | |||||||||||||||||||||
Версия локального кластера | 6.8 | 7.1–7.16 | 7.17 | 8.0 | 8.1 | 8.2 | 8.3 | 8.4 | 8.5 | 8.6 | 8.7 | 8.8 | 8.9 | 8.10 | 8.11 | 8.12 | 8.13 | 8.14 | 8.15 | 8.16 | 8.17 |
6.8 | |||||||||||||||||||||
7.1–7.16 | |||||||||||||||||||||
7.17 | |||||||||||||||||||||
8.0 | |||||||||||||||||||||
8.1 | |||||||||||||||||||||
8.2 | |||||||||||||||||||||
8.3 | |||||||||||||||||||||
8.4 | |||||||||||||||||||||
8.5 | |||||||||||||||||||||
8.6 |
8.7 | |||||||||||||||||||||
8.8 | |||||||||||||||||||||
8.9 | |||||||||||||||||||||
8.10 | |||||||||||||||||||||
8.11 |
8.12 | |||||||||||||||||||||
8.13 | |||||||||||||||||||||
8.14 | |||||||||||||||||||||
8.15 | |||||||||||||||||||||
8.16 |
8.17 |
Для API поиска EQL, локальный и удалённый кластеры должны использовать одну и ту же версию Elasticsearch, если у них версии ниже 7.17.7 (включительно) или ниже 8.5.1 (включительно).
Например, локальный кластер 8.0 может искать в удалённом кластере 7.17 или любом удалённом кластере 8.x. Однако поиск из локального кластера 8.0 в удалённый кластер 7.16 или 6.8 не поддерживается.
Поддерживаются только те функции, которые существуют во всех искомых кластерах. Использование функции с удалённым кластером, где функция не поддерживается, приведёт к неопределённому поведению.
Поиск между кластерами с недопустимой конфигурацией может всё ещё работать. Однако такие поиски не тестируются Elastic, и их поведение не гарантируется.
Обеспечение поддержки поиска между кластерами
Самый простой способ гарантировать поддержку поиска между кластерами — это поддерживать каждый кластер на одной версии Elasticsearch. Если вам нужно поддерживать кластеры с различными версиями, вы можете:
- Поддерживать выделенный кластер для поиска между кластерами. Этот кластер должен поддерживать самую раннюю необходимую версию для поиска в других кластерах. Например, если у вас есть кластеры 7.17 и 8.x, вы можете поддерживать выделенный кластер 7.17 для использования в качестве локального кластера для поиска между кластерами.
- Поддерживать каждый кластер с разницей не более одной мажорной версии. Это позволяет использовать любой кластер в качестве локального кластера при выполнении поиска между кластерами.
Поиск между кластерами во время обновления
Вы по-прежнему можете искать в удалённом кластере во время выполнения плавного обновления локального кластера. Однако версия локального координирующего узла «обновление с» и «обновление до» должна быть совместима с версией узла шлюза удалённого кластера.
Запуск нескольких версий Elasticsearch в одном кластере за пределами периода обновления не поддерживается.
Дополнительную информацию об обновлениях см. в Руководстве по обновлению Elasticsearch.
© 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/modules-cross-cluster-search.html