排查搜索问题

编辑

当您查询数据时,Elasticsearch 可能会返回错误、没有搜索结果或结果顺序不符合预期。本指南描述了如何排查搜索问题。

确保数据流、索引或别名存在

编辑

当您尝试查询的数据流、索引或别名不存在时,Elasticsearch 会返回 index_not_found_exception。当您拼写错误名称或数据已被索引到不同的数据流或索引时,可能会发生这种情况。

使用 exists API 来检查数据流、索引或别名是否存在

resp = client.indices.exists(
    index="my-data-stream",
)
print(resp)
response = client.indices.exists(
  index: 'my-data-stream'
)
puts response
const response = await client.indices.exists({
  index: "my-data-stream",
});
console.log(response);
HEAD my-data-stream

使用 数据流统计 API 列出所有数据流

resp = client.indices.data_streams_stats(
    human=True,
)
print(resp)
response = client.indices.data_streams_stats(
  human: true
)
puts response
const response = await client.indices.dataStreamsStats({
  human: "true",
});
console.log(response);
GET /_data_stream/_stats?human=true

使用 获取索引 API 列出所有索引及其别名

resp = client.indices.get(
    index="_all",
    filter_path="*.aliases",
)
print(resp)
response = client.indices.get(
  index: '_all',
  filter_path: '*.aliases'
)
puts response
const response = await client.indices.get({
  index: "_all",
  filter_path: "*.aliases",
});
console.log(response);
GET _all?filter_path=*.aliases

如果正在查询的某些索引不可用,则可能不会返回错误,而是检索到部分搜索结果。将 ignore_unavailable 设置为 true

resp = client.search(
    index="my-alias",
    ignore_unavailable=True,
)
print(resp)
response = client.search(
  index: 'my-alias',
  ignore_unavailable: true
)
puts response
const response = await client.search({
  index: "my-alias",
  ignore_unavailable: "true",
});
console.log(response);
GET /my-alias/_search?ignore_unavailable=true

确保数据流或索引包含数据

编辑

当搜索请求未返回任何匹配项时,数据流或索引可能不包含数据。当数据摄取出现问题时,可能会发生这种情况。例如,数据可能已被索引到另一个名称的数据流或索引中。

使用 计数 API 来检索数据流或索引中的文档数。检查响应中的 count 是否不为 0。

resp = client.count(
    index="my-index-000001",
)
print(resp)
response = client.count(
  index: 'my-index-000001'
)
puts response
const response = await client.count({
  index: "my-index-000001",
});
console.log(response);
GET /my-index-000001/_count

当在 Kibana 中没有获得任何搜索结果时,请检查您是否选择了正确的数据视图和有效的时间范围。此外,请确保已使用正确的时间字段配置了数据视图。

检查字段是否存在及其功能

编辑

查询不存在的字段将不会返回任何结果。使用 字段功能 API 来检查字段是否存在

resp = client.field_caps(
    index="my-index-000001",
    fields="my-field",
)
print(resp)
response = client.field_caps(
  index: 'my-index-000001',
  fields: 'my-field'
)
puts response
const response = await client.fieldCaps({
  index: "my-index-000001",
  fields: "my-field",
});
console.log(response);
GET /my-index-000001/_field_caps?fields=my-field

如果该字段不存在,请检查数据摄取过程。该字段可能具有不同的名称。

如果该字段存在,则请求将返回该字段的类型以及是否可搜索和可聚合。

{
  "indices": [
    "my-index-000001"
  ],
  "fields": {
    "my-field": {
      "keyword": {
        "type": "keyword",         
        "metadata_field": false,
        "searchable": true,        
        "aggregatable": true       
      }
    }
  }
}

该字段在此索引中的类型为 keyword

该字段在此索引中可搜索。

该字段在此索引中可聚合。

检查字段的映射

编辑

字段的功能由其映射决定。要检索映射,请使用 获取映射 API

resp = client.indices.get_mapping(
    index="my-index-000001",
)
print(resp)
response = client.indices.get_mapping(
  index: 'my-index-000001'
)
puts response
const response = await client.indices.getMapping({
  index: "my-index-000001",
});
console.log(response);
GET /my-index-000001/_mappings

如果您查询 text 字段,请注意可能已配置的分析器。您可以使用 分析 API 来检查字段的分析器如何处理值和查询词

resp = client.indices.analyze(
    index="my-index-000001",
    field="my-field",
    text="this is a test",
)
print(resp)
response = client.indices.analyze(
  index: 'my-index-000001',
  body: {
    field: 'my-field',
    text: 'this is a test'
  }
)
puts response
const response = await client.indices.analyze({
  index: "my-index-000001",
  field: "my-field",
  text: "this is a test",
});
console.log(response);
GET /my-index-000001/_analyze
{
  "field" : "my-field",
  "text" : "this is a test"
}

要更改现有字段的映射,请参阅 更改字段的映射

检查字段的值

编辑

使用 exists 查询来检查是否有文档为字段返回值。检查响应中的 count 是否不为 0。

resp = client.count(
    index="my-index-000001",
    query={
        "exists": {
            "field": "my-field"
        }
    },
)
print(resp)
response = client.count(
  index: 'my-index-000001',
  body: {
    query: {
      exists: {
        field: 'my-field'
      }
    }
  }
)
puts response
const response = await client.count({
  index: "my-index-000001",
  query: {
    exists: {
      field: "my-field",
    },
  },
});
console.log(response);
GET /my-index-000001/_count
{
  "query": {
    "exists": {
      "field": "my-field"
    }
  }
}

如果该字段可聚合,您可以使用 聚合 来检查字段的值。对于 keyword 字段,您可以使用 词项聚合 来检索字段的最常见值

resp = client.search(
    index="my-index-000001",
    filter_path="aggregations",
    size=0,
    aggs={
        "top_values": {
            "terms": {
                "field": "my-field",
                "size": 10
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'my-index-000001',
  filter_path: 'aggregations',
  body: {
    size: 0,
    aggregations: {
      top_values: {
        terms: {
          field: 'my-field',
          size: 10
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "my-index-000001",
  filter_path: "aggregations",
  size: 0,
  aggs: {
    top_values: {
      terms: {
        field: "my-field",
        size: 10,
      },
    },
  },
});
console.log(response);
GET /my-index-000001/_search?filter_path=aggregations
{
  "size": 0,
  "aggs": {
    "top_values": {
      "terms": {
        "field": "my-field",
        "size": 10
      }
    }
  }
}

对于数值字段,您可以使用 统计聚合 来了解字段的值分布

resp = client.search(
    index="my-index-000001",
    filter_path="aggregations",
    aggs={
        "my-num-field-stats": {
            "stats": {
                "field": "my-num-field"
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'my-index-000001',
  filter_path: 'aggregations',
  body: {
    aggregations: {
      "my-num-field-stats": {
        stats: {
          field: 'my-num-field'
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "my-index-000001",
  filter_path: "aggregations",
  aggs: {
    "my-num-field-stats": {
      stats: {
        field: "my-num-field",
      },
    },
  },
});
console.log(response);
GET my-index-000001/_search?filter_path=aggregations
{
  "aggs": {
    "my-num-field-stats": {
      "stats": {
        "field": "my-num-field"
      }
    }
  }
}

如果该字段未返回任何值,请检查数据摄取过程。该字段可能具有不同的名称。

检查最新值

编辑

对于时间序列数据,请确认在尝试的时间范围内存在未过滤的数据。例如,如果您尝试查询 @timestamp 字段的最新数据,请运行以下命令以查看最大 @timestamp 是否在尝试的范围内

resp = client.search(
    index="my-index-000001",
    sort="@timestamp:desc",
    size="1",
)
print(resp)
response = client.search(
  index: 'my-index-000001',
  sort: '@timestamp:desc',
  size: 1
)
puts response
const response = await client.search({
  index: "my-index-000001",
  sort: "@timestamp:desc",
  size: 1,
});
console.log(response);
GET my-index-000001/_search?sort=@timestamp:desc&size=1

验证、解释和分析查询

编辑

当查询返回意外结果时,Elasticsearch 提供了几种工具来调查原因。

验证 API 使您能够验证查询。使用 rewrite 参数来返回 Elasticsearch 查询被重写成的 Lucene 查询

resp = client.indices.validate_query(
    index="my-index-000001",
    rewrite=True,
    query={
        "match": {
            "user.id": {
                "query": "kimchy",
                "fuzziness": "auto"
            }
        }
    },
)
print(resp)
response = client.indices.validate_query(
  index: 'my-index-000001',
  rewrite: true,
  body: {
    query: {
      match: {
        'user.id' => {
          query: 'kimchy',
          fuzziness: 'auto'
        }
      }
    }
  }
)
puts response
const response = await client.indices.validateQuery({
  index: "my-index-000001",
  rewrite: "true",
  query: {
    match: {
      "user.id": {
        query: "kimchy",
        fuzziness: "auto",
      },
    },
  },
});
console.log(response);
GET /my-index-000001/_validate/query?rewrite=true
{
  "query": {
    "match": {
      "user.id": {
        "query": "kimchy",
        "fuzziness": "auto"
      }
    }
  }
}

使用 解释 API 来查明为什么特定的文档与查询匹配或不匹配

resp = client.explain(
    index="my-index-000001",
    id="0",
    query={
        "match": {
            "message": "elasticsearch"
        }
    },
)
print(resp)
response = client.explain(
  index: 'my-index-000001',
  id: 0,
  body: {
    query: {
      match: {
        message: 'elasticsearch'
      }
    }
  }
)
puts response
const response = await client.explain({
  index: "my-index-000001",
  id: 0,
  query: {
    match: {
      message: "elasticsearch",
    },
  },
});
console.log(response);
GET /my-index-000001/_explain/0
{
  "query" : {
    "match" : { "message" : "elasticsearch" }
  }
}

分析 API 提供了有关搜索请求的详细计时信息。要查看结果的可视化表示,请使用 Kibana 中的 搜索分析器

要在 Kibana 中排查查询问题,请在工具栏中选择 检查。接下来,选择 请求。现在,您可以复制 Kibana 发送到 Elasticsearch 的查询,以便在控制台中进行进一步分析。

检查索引设置

编辑

索引设置可能会影响搜索结果。例如,index.query.default_field 设置,它确定当查询未指定显式字段时查询的字段。使用 获取索引设置 API 来检索索引的设置

resp = client.indices.get_settings(
    index="my-index-000001",
)
print(resp)
response = client.indices.get_settings(
  index: 'my-index-000001'
)
puts response
const response = await client.indices.getSettings({
  index: "my-index-000001",
});
console.log(response);
GET /my-index-000001/_settings

您可以使用 更新索引设置 API 来更新动态索引设置。更改数据流的动态索引设置需要更改数据流使用的索引模板。

对于静态设置,您需要使用正确的设置创建一个新索引。接下来,您可以将数据重新索引到该索引中。对于数据流,请参阅 更改数据流的静态索引设置

查找慢查询

编辑

慢日志可以帮助查明性能较慢的搜索请求。在顶部启用 审计日志记录 可以帮助确定查询来源。将以下设置添加到 elasticsearch.yml 配置文件以跟踪查询。生成的日志记录非常详细,因此在不进行故障排除时请禁用这些设置。

xpack.security.audit.enabled: true
xpack.security.audit.logfile.events.include: _all
xpack.security.audit.logfile.events.emit_request_body: true

有关更多信息,请参阅 高级调整:查找和修复慢速 Elasticsearch 查询