30、Elasticsearch 查询高级操作指南

Elasticsearch 查询高级操作指南

1. 相关性得分解释

Elasticsearch 提供了一种机制来理解相关性得分的构成,该机制能准确告诉我们引擎是如何计算得分的。可以通过在搜索端点使用 explain 标志或使用 explain API 来实现。

1.1 explain 标志

有些查询结果中会出现一个正数(相关性得分值),但我们可能不清楚它是如何计算的。Elasticsearch 提供了一个名为 explain 的标志,我们可以在查询体中设置该标志。若将 explain 属性设置为 true ,Elasticsearch 会返回结果,并详细说明得分是如何得出的。

示例代码如下:

GET movies/_search
{
  "explain": true,  
  "_source": false,  
  "query": {
    "match": {
      "title": "Lord"
    }
  }
}

相关性得分由三个组件相乘得出:逆文档频率(idf)、词频(tf)和提升因子。idf 的计算公式为:
[
idf = \log(1 + \frac{N - n + 0.5}{n + 0.5})
]
其中:
- (n) 是包含该术语的文档总数。
- (N) 是文档的总数。

词频(tf)的计算公式为:
[
tf = \frac{freq}{freq + k1 * (1 - b + b * \frac{dl}{avgdl})}
]

如果查询没有匹配结果,比如将 Lord 拼写为 Lords 进行搜索,结果将为空。

1.2 explain API

除了使用 explain 属性理解相关性得分机制外, explain API 还能深入解释文档匹配(或不匹配)的原因,并提供得分计算。

示例代码如下:

GET movies/_explain/14
{
  "query":{
    "match": {
      "title": "Lord"
    }
  }
}

若将 match 属性中的 Lord 拼写为 Lords 并重新运行查询,会得到不匹配的提示:

{
  "_index" : "movies",
  "_type" : "_doc",
  "_id" : "14",
  "matched" : false,
  "explanation" : {
    "value" : 0.0,
    "description" : "no matching term",
    "details" : [ ]
  }
}

使用 _search API explain 标志构建的搜索查询可能会产生大量结果,询问查询级别所有文档的得分解释会浪费计算资源。建议选择一个文档,使用 _explain API 进行解释。

2. 结果排序

引擎返回的结果默认按相关性得分( _score )排序,得分越高,在返回列表中的位置越靠前。但 Elasticsearch 不仅允许我们管理相关性得分的排序顺序(从升序到降序),还可以按其他字段(包括多个字段)进行排序。

2.1 结果排序操作

要对结果进行排序,需在与查询同级的位置提供一个 sort 对象。 sort 对象由一个字段数组组成,每个字段包含一些可调整的参数。

示例代码如下:

GET movies/_search
{
  "query": {
    "match": {
      "genre": "crime"
    }
  },
  "sort": [
     { "rating" :{ "order": "desc" } }
  ]
}

此查询搜索犯罪类型的所有电影,并按电影评分降序排序。

2.2 按相关性得分排序

若查询中未指定排序,携带相关性得分的文档默认按 _score 降序排序。

示例代码如下:

GET movies/_search  
{
  "size": 10,  
  "query": {
    "match": {
      "title": "Godfather"
    }
  }
}

等价于以下代码:

GET movies/_search
{
  "size": 10,  
  "query": {
    "match": {
      "title": "Godfather"
    }
  },
  "sort": [ 
    "_score" 
  ]
}

若要按升序排序,可使用以下代码:

GET movies/_search
{
  "size": 10,  
  "query": {
    "match": {
      "title": "Godfather"
    }
  },
  "sort": [
    {"_score":{"order":"asc"}}
  ]
}

按非得分文档字段排序的示例代码如下:

GET movies/_search
{
  "size": 10,  
  "query": {
    "match": {
      "genre": "crime"
    }
  },
  "sort": [
    {"rating":{"order":"desc"}}
  ]
}

使用任何字段进行排序时,Elasticsearch 不会计算得分。但可以使用 track_scores 布尔字段要求 Elasticsearch 计算得分。

示例代码如下:

GET movies/_search
{
  "track_scores":true,
  "size": 10,  
  "query": {
    "match": {
      "genre": "crime"
    }
  },
  "sort": [
    {"rating":{"order":"asc"}}
  ]
}

还可以按多个字段进行排序,例如按评分和发布日期升序排序:

GET movies/_search
{
  "size": 10,  
  "query": {
    "match": {
      "genre": "crime"
    }
  },
  "sort": [
    {"rating":{"order":"asc"}},
    {"release_date":{"order":"asc"}}
  ]
}

按多个字段排序时,排序顺序很重要。先按评分升序排序,若电影评分相同,则按发布日期升序排序。

3. 结果操作

搜索查询通常返回 _source 字段指定的原始文档结果。但有时我们可能只需要部分字段,或者不希望引擎在响应中返回整个文档。Elasticsearch 允许我们对响应进行操作。

3.1 抑制完整文档

要抑制搜索响应中返回的文档,只需在查询中将 _source 标志设置为 false

示例代码如下:

GET movies/_search
{
  "_source": false,  
  "query": {
    "match": {
      "certificate": "R"
    }
  }
}

响应将只包含元数据。

3.2 获取选定字段

可以使用 fields 对象指定要返回的字段。

示例代码如下:

GET movies/_search
{
  "_source": false,  
  "query": {
    "match": {
      "certificate": "R"
    }
  },
  "fields": [
    "title",
    "rating"
  ]
}

每个字段都会以数组形式返回,因为 Elasticsearch 期望有多个值。也可以在字段映射中使用通配符,例如设置 title* 可以检索所有以 title 为前缀的字段。

3.3 脚本字段

有时需要动态计算一个字段并添加到响应中。可以使用脚本功能,在查询中追加 script_fields 对象。

示例代码如下:

GET movies/_search
{
  "_source": ["title*","synopsis", "rating"],  
  "query": {
    "match": {
      "certificate": "R"
    }
  },
  "script_fields": {
    "top_rated_movie": {
      "script": {
        "lang": "painless",
        "source": "if (doc['rating'].value > 9.0) 'true'; else 'false'"
      }
    }
  }
}

此代码创建了一个新字段 top_rated_movie ,如果电影评分大于 9,则标记为 true ,否则为 false

3.4 源过滤

可以通过设置 _source 选项来进一步调整返回的字段。可以指定要包含和排除的字段列表。

示例代码如下:

GET movies/_search
{
  "_source": ["title*","synopsis", "rating"],  
  "query": {
    "match": {
      "certificate": "R"
    }
  }
}

还可以使用 includes excludes 数组进行更精细的控制。

示例代码如下:

GET movies/_search
{
  "_source": {
    "includes": ["title*","synopsis","genre"],
    "excludes": ["title.original"]
  },  
  "query": {
    "match": {
      "certificate": "R"
    }
  }
}

_source 对象期望两个数组:
- includes :包含所有期望在结果中返回的字段。
- excludes :定义要从 includes 列表返回的字段中排除的字段列表。

4. 跨索引和数据流搜索

数据通常会分散在多个索引和数据流中。Elasticsearch 允许我们通过在搜索请求中追加所需的索引来跨多个索引和数据流搜索数据。

4.1 跨所有索引搜索

省略搜索请求中的索引名称,引擎会搜索所有索引。

示例代码如下:

GET _search
{
  "query": {
    "match": {
      "actors": "Pacino"
    }
  }
}

也可以使用 GET */_search GET _all/_search ,效果相同。

4.2 提升索引

跨多个索引搜索时,可能希望某个索引中的文档比另一个索引中的相同文档更优先。可以在查询对象同级位置附加 indices_boost 对象。

示例代码如下:

GET movies*/_search
{
  "indices_boost": [
    { "movies": 0.1},
    { "movies_new": 0}, 
    { "movies_top": 2.0} 
  ],  
  "query": {
    "match": {
      "title": "Redemption"
    }
  }
}

此查询将 movies_top 索引中的文档得分提高两倍,将 movies 索引中的文档得分降低到 0.1,将 movies_new 索引中的文档得分设置为 0。

总结

  • 搜索可分为结构化和非结构化搜索类型。
  • 结构化数据适用于非文本字段,如数字和日期字段,或在索引时不进行分析的字段,产生二进制结果(存在或不存在)。
  • 非结构化数据处理文本字段,期望带有相关性得分,引擎根据结果文档与标准的匹配程度对结果进行评分。
  • 结构化查询使用词级搜索,非结构化数据使用全文搜索。
  • 每个搜索请求由一个协调器节点处理,协调器节点负责要求其他节点执行查询、返回部分数据、聚合数据并向客户端返回最终结果。
  • Elasticsearch 提供 _search 端点进行查询和聚合,可以使用带参数的 URI 请求或使用 Query DSL 构建完整请求来调用该端点。
  • Query DSL 是创建搜索查询的首选,可构建大量查询,包括高级查询。
  • Query DSL 允许创建叶子查询和复合查询,叶子查询是具有单个条件的简单搜索查询,复合查询用于结合条件子句的高级查询。
  • 大多数类型的查询都有一些通用功能,如分页、高亮显示、得分解释、结果操作等。

以下是一个简单的 mermaid 流程图,展示搜索的基本流程:

graph TD;
    A[发起搜索请求] --> B[协调器节点接收请求];
    B --> C[协调器节点请求其他节点执行查询];
    C --> D[其他节点返回部分数据];
    D --> E[协调器节点聚合数据];
    E --> F[协调器节点向客户端返回最终结果];
操作类型 描述 示例代码
相关性得分解释 使用 explain 标志或 explain API 解释得分计算 见上文 explain 标志和 explain API 部分代码
结果排序 按相关性得分或其他字段排序 见上文排序部分代码
结果操作 抑制文档、获取选定字段、使用脚本字段、源过滤 见上文结果操作部分代码
跨索引和数据流搜索 跨所有索引搜索或提升特定索引 见上文跨索引和数据流搜索部分代码

Elasticsearch 查询高级操作指南

5. 操作总结与对比

为了更清晰地展示前面介绍的各项操作,下面通过表格进行总结对比:
| 操作类别 | 具体操作 | 作用 | 示例代码 |
| ---- | ---- | ---- | ---- |
| 相关性得分解释 | explain 标志 | 详细说明查询结果的得分计算过程 |

GET movies/_search
{
  "explain": true,  
  "_source": false,  
  "query": {
    "match": {
      "title": "Lord"
    }
  }
}
``` |
| 相关性得分解释 | `explain API` | 解释文档匹配(或不匹配)原因并提供得分计算 |
```json
GET movies/_explain/14
{
  "query":{
    "match": {
      "title": "Lord"
    }
  }
}
``` |
| 结果排序 | 按单一字段排序 | 按指定字段对查询结果进行排序 |
```json
GET movies/_search
{
  "query": {
    "match": {
      "genre": "crime"
    }
  },
  "sort": [
     { "rating" :{ "order": "desc" } }
  ]
}
``` |
| 结果排序 | 按相关性得分排序(降序) | 默认按相关性得分降序排列结果 |
```json
GET movies/_search  
{
  "size": 10,  
  "query": {
    "match": {
      "title": "Godfather"
    }
  }
}
``` |
| 结果排序 | 按相关性得分排序(升序) | 按相关性得分升序排列结果 |
```json
GET movies/_search
{
  "size": 10,  
  "query": {
    "match": {
      "title": "Godfather"
    }
  },
  "sort": [
    {"_score":{"order":"asc"}}
  ]
}
``` |
| 结果排序 | 按多个字段排序 | 按多个指定字段依次排序 |
```json
GET movies/_search
{
  "size": 10,  
  "query": {
    "match": {
      "genre": "crime"
    }
  },
  "sort": [
    {"rating":{"order":"asc"}},
    {"release_date":{"order":"asc"}}
  ]
}
``` |
| 结果操作 | 抑制完整文档 | 不返回原始文档,只返回元数据 |
```json
GET movies/_search
{
  "_source": false,  
  "query": {
    "match": {
      "certificate": "R"
    }
  }
}
``` |
| 结果操作 | 获取选定字段 | 返回指定的部分字段 |
```json
GET movies/_search
{
  "_source": false,  
  "query": {
    "match": {
      "certificate": "R"
    }
  },
  "fields": [
    "title",
    "rating"
  ]
}
``` |
| 结果操作 | 脚本字段 | 动态计算字段并添加到响应中 |
```json
GET movies/_search
{
  "_source": ["title*","synopsis", "rating"],  
  "query": {
    "match": {
      "certificate": "R"
    }
  },
  "script_fields": {
    "top_rated_movie": {
      "script": {
        "lang": "painless",
        "source": "if (doc['rating'].value > 9.0) 'true'; else 'false'"
      }
    }
  }
}
``` |
| 结果操作 | 源过滤 | 精细控制返回的字段 |
```json
GET movies/_search
{
  "_source": {
    "includes": ["title*","synopsis","genre"],
    "excludes": ["title.original"]
  },  
  "query": {
    "match": {
      "certificate": "R"
    }
  }
}
``` |
| 跨索引和数据流搜索 | 跨所有索引搜索 | 搜索所有索引中的数据 |
```json
GET _search
{
  "query": {
    "match": {
      "actors": "Pacino"
    }
  }
}
``` |
| 跨索引和数据流搜索 | 提升索引 | 提高特定索引中文档的优先级 |
```json
GET movies*/_search
{
  "indices_boost": [
    { "movies": 0.1},
    { "movies_new": 0}, 
    { "movies_top": 2.0} 
  ],  
  "query": {
    "match": {
      "title": "Redemption"
    }
  }
}
``` |

#### 6. 操作流程梳理
下面通过 mermaid 流程图,梳理不同操作的整体流程:
```mermaid
graph LR;
    classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
    classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;

    A([开始]):::startend --> B{选择操作类型}:::decision;
    B -->|相关性得分解释| C(设置 `explain` 标志或使用 `explain API`):::process;
    C --> D(获取得分计算解释):::process;
    B -->|结果排序| E(设置 `sort` 对象):::process;
    E --> F(按指定规则排序结果):::process;
    B -->|结果操作| G(根据需求设置 `_source`、`fields`、`script_fields` 等):::process;
    G --> H(获取处理后的结果):::process;
    B -->|跨索引和数据流搜索| I(设置索引和 `indices_boost` 对象):::process;
    I --> J(跨索引搜索并调整优先级):::process;
    D --> K([结束]):::startend;
    F --> K;
    H --> K;
    J --> K;
7. 实际应用场景分析
  • 内容推荐系统 :在内容推荐系统中,通常需要根据用户的兴趣进行搜索和排序。例如,根据用户历史浏览的电影类型,使用跨索引和数据流搜索功能,从多个索引中搜索相关电影。同时,使用相关性得分解释功能,分析推荐结果的相关性得分,确保推荐的准确性。还可以通过脚本字段功能,动态计算电影的推荐指数,如结合电影的评分、评论数量等因素。
  • 日志分析系统 :在日志分析系统中,数据通常分散在多个索引中。可以使用跨索引和数据流搜索功能,快速搜索所有日志数据。通过结果排序功能,按时间或重要性对日志进行排序,方便分析人员查看。使用结果操作功能,只获取关键的日志字段,提高查询效率。
8. 注意事项
  • 资源消耗 :使用 explain 标志解释所有文档的得分计算会消耗大量计算资源,建议只对特定文档使用 _explain API 进行解释。
  • 排序与得分计算 :当使用除 _score 以外的字段进行排序时,Elasticsearch 默认不计算得分。如果需要得分信息,要设置 track_scores true
  • 字段数组形式 :使用 fields 对象获取选定字段时,每个字段会以数组形式返回,因为 Elasticsearch 期望有多个值。

通过掌握 Elasticsearch 的这些高级操作,能够更灵活地处理搜索查询,满足不同场景下的需求,提高搜索效率和结果的准确性。希望以上内容能帮助你更好地运用 Elasticsearch 进行数据搜索和分析。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值