Skip to content
Gains Summary
Main Navigation 首页 / Home
C++ 编程 / C++ Programming
系统与高性能 / Systems & Performance
Web 开发 / Web Development
人工智能 / Artificial Intelligence
工业软件 / Industrial Software
其他内容 / Other Topics
C++ 编程 / C++系统与性能 / SystemsWeb 开发 / Web人工智能 / AI工业软件 / Industrial

外观

Sidebar Navigation

← Web 开发 / Web Development

中间件 / Middleware

1. Web 中间件全景 / The Web Middleware Landscape

2. 中间件——流量洪峰下的系统保护 / Middleware for Protecting Systems Under Traffic Spikes

cache layer

1. 缓存架构全景 / Cache Architecture Overview

2. Redis 深入——为什么你的缓存总是出问题 / Redis Internals and Cache Failure Modes

3. Redis 数据结构场景应用——什么时候用什么 / Choosing Redis Data Structures for Real Applications

4. 缓存策略——库存变了,缓存怎么处理 / Cache Strategies and Inventory Consistency

5. Redis 缓存三剑客——穿透/击穿/雪崩 + 一致性策略 / Redis Cache Penetration, Breakdown, Avalanche, and Consistency

6. Redis 分布式锁——从 SETNX 到 Redisson / Redis Distributed Locks from SETNX to Redisson

7. Redis Cluster 与 Sentinel 高可用架构 / Redis Cluster and Sentinel High-Availability Architecture

8. Redis 高级特性——Stream / PubSub / Module / LLM 应用

9. Redis 架构深度分析——为什么 Redis 能这么快 / Redis Architecture and the Sources of Its Performance

10. Redis 全景——为什么你的系统需要一个缓存层 / The Redis Landscape and Why Systems Need a Cache Layer

message queue

1. 消息队列全景——为什么你的系统需要一个中间人 / Message Queue Overview and Why Your System Needs a Middleman

2. Kafka 核心——为什么你的消息总是"丢"了 / Kafka Fundamentals and Message Delivery Semantics

3. 消息队列高级——死信队列、延迟消息、消息积压 / Advanced Messaging with Dead Letters, Delays, and Backlogs

4. Kafka Streams 与 Connect —— 让数据自己流动起来 / Kafka Streams and Connect for Streaming Data Pipelines

5. RabbitMQ 深度解析 —— 灵活路由与消息可靠性 / RabbitMQ Deep Dive into Flexible Routing and Reliability

6. 消息队列对比——为什么最终选了 Kafka / Comparing Message Queues and Choosing Kafka

search engine

1. 搜索引擎知识体系 / Search Engine Knowledge System

2. Elasticsearch——为什么 Like 查询总是那么慢 / Elasticsearch for Full-Text Search at Scale

3. Elasticsearch 查询 DSL 深入——为什么你的搜索总是不准 / Elasticsearch Query DSL Deep Dive

4. Elasticsearch 集群规划与运维——为什么你的集群总是"黄" / Elasticsearch Cluster Planning and Operations

5. Meilisearch 与轻量搜索替代方案——当 ES 太重时 / Meilisearch and Lightweight Search Alternatives

infrastructure

1. 基础设施组件全景 / Infrastructure Components Landscape

2. Nginx 与反向代理 / Nginx and Reverse Proxy

3. 服务发现 / Service Discovery

4. 配置中心 / Configuration Center

本页目录

Elasticsearch 查询 DSL 深入——为什么你的搜索总是不准 / Elasticsearch Query DSL Deep Dive ​

📅 创建时间:2026-07-28 🏷️ 标签:#Elasticsearch #QueryDSL #全文搜索 #聚合 #BM25 #相关性调优 📚 前置知识:[[./00-overview]](搜索引擎概览) [[/03-web/07-middleware/06-elasticsearch]](ES 倒排索引基础)


📋 本章目标 ​

  • 理解 Query Context 与 Filter Context 的本质区别(score vs no-score)
  • 掌握核心全文查询:match、multi_match、match_phrase、query_string
  • 掌握复合查询:bool、boosting、dis_max 的组合策略
  • 理解 Aggregations 的三种类型:Bucket / Metrics / Pipeline
  • 能够调优相关性评分:BM25 参数、boosting、function_score、script_score
  • 掌握六种常见搜索模式的实现:跨字段、模糊、自动补全、地理位置、嵌套、高亮
  • 学会诊断查询性能:Profile API、慢查询日志、filter 缓存、routing

第1部分:Query Context vs Filter Context ​

1.1 两种上下文的本质区别 ​

在 ES 中,每一次查询操作都在两种"上下文"中选择:这个条件是用来打分(Query Context)还是用来筛选(Filter Context)?这是理解 ES 查询性能的第一步。

┌─────────────────────────────────────────────────────────────┐
│                Query Context vs Filter Context               │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Query Context(查询上下文):                               │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  "这个文档和用户的查询有多匹配?"                     │   │
│  │                                                     │   │
│  │  • 会计算相关性得分 (_score)                          │   │
│  │  • 得分影响排序                                       │   │
│  │  • 不缓存(每次都重新算分)                           │   │
│  │  • 举例:"标题里包含'小米手机'的文档"                │   │
│  │    → 完全匹配的得分高,部分匹配的得分低               │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  Filter Context(过滤上下文):                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  "这个文档符合条件吗?是或否"                          │   │
│  │                                                     │   │
│  │  • 不计算评分(_score 为 0 或忽略)                   │   │
│  │  • 只做二选一的过滤                                    │   │
│  │  • 自动缓存(ES 内置 filter cache)                  │   │
│  │  • 举例:"价格在 1000-5000 之间"                     │   │
│  │    → 1001 元和 4999 元没有区别,都是"符合"           │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  核心原则:                                                 │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  ✅ 全文匹配 → Query Context(match)                │   │
│  │  ✅ 精确筛选 → Filter Context(term, range)         │   │
│  │  ✅ 两者组合 → bool 查询(must + filter)            │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

1.2 实践:同一个条件的不同写法 ​

┌─────────────────────────────────────────────────────────────┐
│              同一条件的三种写法及其行为                       │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  场景:查找 category 为 "phone" 且标题包含 "小米" 的商品   │
│                                                             │
│  写法1:全部用 Query Context(不推荐)                      │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  {                                                    │   │
│  │    "query": {                                         │   │
│  │      "bool": {                                        │   │
│  │        "must": [                                      │   │
│  │          {"match": {"category": "phone"}},  // ← Q   │   │
│  │          {"match": {"title": "小米"}}       // ← Q   │   │
│  │        ]                                              │   │
│  │      }                                                │   │
│  │    }                                                  │   │
│  │  }                                                    │   │
│  │  问题:category 精确匹配不需要打分,浪费 CPU          │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  写法2:Query + Filter(推荐)                              │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  {                                                    │   │
│  │    "query": {                                         │   │
│  │      "bool": {                                        │   │
│  │        "must": [                                      │   │
│  │          {"match": {"title": "小米"}}       // Q     │   │
│  │        ],                                             │   │
│  │        "filter": [                                    │   │
│  │          {"term": {"category": "phone"}}    // F     │   │
│  │        ]                                              │   │
│  │      }                                                │   │
│  │    }                                                  │   │
│  │  }                                                    │   │
│  │  优点:filter 条件自动缓存,不参与评分                │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  写法3:post_filter(特定场景)                              │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  {                                                    │   │
│  │    "query": {"match": {"title": "小米"}},             │   │
│  │    "post_filter": {"term": {"category": "phone"}}     │   │
│  │  }                                                    │   │
│  │  注意:post_filter 在聚合计算之后才过滤               │   │
│  │  适用:需要"全量聚合 + 部分过滤结果的聚合"时         │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

第2部分:全文查询 ​

2.1 match —— 最常用的全文查询 ​

┌─────────────────────────────────────────────────────────────┐
│                    match 查询详解                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  match 查询会自动分词,然后对每个词做 term 查询后取 OR      │
│                                                             │
│  示例:                                                     │
│  {"match": {"title": "小米手机"}}                           │
│         ↓ 分词 (ik_max_word)                                │
│  [小米, 手机]                                               │
│         ↓ 转为 Lucene 查询                                  │
│  title:小米 OR title:手机                                   │
│                                                             │
│  控制匹配精度:operator 参数                                │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  {"match": {                                         │   │
│  │    "title": {                                        │   │
│  │      "query": "小米手机",                             │   │
│  │      "operator": "and"    // 改为 AND                │   │
│  │    }                                                 │   │
│  │  }}                                                  │   │
│  │  → title:小米 AND title:手机                         │   │
│  │  → 必须同时包含"小米"和"手机"                        │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  控制模糊度:minimum_should_match                           │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  {"match": {                                         │   │
│  │    "title": {                                        │   │
│  │      "query": "小米 13 Pro 手机",                    │   │
│  │      "minimum_should_match": "75%"  // 至少匹配75%   │   │
│  │    }                                                 │   │
│  │  }}                                                  │   │
│  │  分词: [小米, 13, Pro, 手机] → 4个词                │   │
│  │  至少匹配 ceil(4*75%) = 3个词                        │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

2.2 multi_match —— 跨字段搜索 ​

┌─────────────────────────────────────────────────────────────┐
│                  multi_match 跨字段搜索                       │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  场景:用户在搜索框输入"小米",你希望同时在 title、        │
│        description、brand 三个字段中搜索                     │
│                                                             │
│  六种匹配模式:                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                                                      │   │
│  │  best_fields (默认):取单个最佳匹配字段的分数        │   │
│  │  ┌──────────────────────────────────────────────┐   │   │
│  │  │  title: "小米"      → score: 8.5  ← 取这个   │   │
│  │  │  description: "小米" → score: 2.1             │   │
│  │  │  brand: "小米"       → score: 5.0             │   │
│  │  │  最终分数: max(8.5, 2.1, 5.0) = 8.5          │   │
│  │  │                                              │   │
│  │  │  适用:搜索词在同一字段里匹配最好             │   │
│  │  │  如搜索"小米手机",title 完整匹配 >          │   │
│  │  │     description 部分匹配                      │   │
│  │  └──────────────────────────────────────────────┘   │   │
│  │                                                      │   │
│  │  most_fields:取所有匹配字段的分数之和               │   │
│  │  ┌──────────────────────────────────────────────┐   │   │
│  │  │  title: "小米"       → score: 5.0            │   │
│  │  │  description: "小米"  → score: 2.0            │   │
│  │  │  最终分数: 5.0 + 2.0 = 7.0                   │   │
│  │  │                                              │   │
│  │  │  适用:同一文本出现在多个字段中应加分         │   │
│  │  └──────────────────────────────────────────────┘   │   │
│  │                                                      │   │
│  │  cross_fields:把多个字段当一个大字段处理            │   │
│  │  ┌──────────────────────────────────────────────┐   │   │
│  │  │  "张三 北京"                                  │   │
│  │  │  first_name: "张三"  address: "北京"          │   │
│  │  │  两个词分散在不同字段,但应该匹配!            │   │
│  │  │                                              │   │
│  │  │  适用:搜索词分散在多个字段中的场景            │   │
│  │  │  如人名+地名、产品名+型号                      │   │
│  │  └──────────────────────────────────────────────┘   │   │
│  │                                                      │   │
│  │  phrase / phrase_prefix / bool_prefix                 │   │
│  │  以 phrase 方式跨字段匹配                             │   │
│  │                                                      │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

2.3 match_phrase —— 短语匹配 ​

┌─────────────────────────────────────────────────────────────┐
│                    match_phrase 短语查询                      │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  match_phrase 要求词按顺序连续出现(利用 Position 数据)     │
│                                                             │
│  示例:                                                     │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  {"match_phrase": {"title": "小米手机"}}             │   │
│  │                                                      │   │
│  │  分词: [小米, 手机]                                   │   │
│  │                                                      │   │
│  │  文档1: "小米 13 手机"                                │   │
│  │    小米(position=0), 手机(position=2)                 │   │
│  │    → 位置差 = 2,不连续 ❌ 不匹配!                   │   │
│  │                                                      │   │
│  │  文档2: "小米手机壳"                                  │   │
│  │    小米(position=0), 手机(position=1)                 │   │
│  │    → 位置差 = 1,连续 ✅ 匹配!                       │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  slop 参数:允许词之间有间隔                                │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  {"match_phrase": {                                   │   │
│  │    "title": {                                         │   │
│  │      "query": "小米手机",                              │   │
│  │      "slop": 2  // 允许词之间最多间隔2个位置          │   │
│  │    }                                                  │   │
│  │  }}                                                   │   │
│  │                                                       │   │
│  │  "小米 13 手机" → slop=1, slop=2 ✅ 匹配             │   │
│  │  "小米 13 Pro 手机" → slop=2, slop=2 ✅ 匹配         │   │
│  │  "小米 13 Pro Max 手机" → slop=3 ❌ 不匹配           │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

2.4 query_string —— 类 Lucene 语法 ​

┌─────────────────────────────────────────────────────────────┐
│                  query_string 高级查询                        │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  query_string 支持类 Lucene 的查询语法,适合高级用户        │
│                                                             │
│  语法速查:                                                 │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  "小米 AND 手机"          → 两个词都必须有           │   │
│  │  "小米 OR 华为"           → 任意一个有               │   │
│  │  "小米 NOT 二手"          → 有小米但没有二手         │   │
│  │  "title:小米"             → 只在 title 字段搜       │   │
│  │  "price:[100 TO 500]"     → 价格范围                 │   │
│  │  "name:/mi.*/"            → 正则匹配                 │   │
│  │  "小米~"                  → 模糊匹配(编辑距离1)    │   │
│  │  "\"小米手机\"~2"         → 短语匹配,slop=2        │   │
│  │  "小米^2 手机"            → boosting,小米权重×2    │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  危险与建议:                                               │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  ⚠️  query_string 容易造成查询错误                      │   │
│  │  用户输入 "NOT" 或特殊字符可能导致意外行为             │   │
│  │                                                      │   │
│  │  ✅ 用户搜索 → match / multi_match                    │   │
│  │  ✅ 后台管理 → query_string(可控的专家查询)          │   │
│  │  ✅ 更安全:simple_query_string(忽略错误语法)         │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

第3部分:复合查询 ​

3.1 bool 查询 —— 一切皆 bool ​

┌─────────────────────────────────────────────────────────────┐
│                    bool 查询四子句                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  在 ES 中,几乎所有复杂查询最终都是 bool 查询的组合:       │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  {                                                    │   │
│  │    "query": {                                         │   │
│  │      "bool": {                                        │   │
│  │        "must":     [...],  // 必须匹配(AND)         │   │
│  │        "should":   [...],  // 应该匹配(OR)          │   │
│  │        "filter":   [...],  // 必须匹配(不评分)      │   │
│  │        "must_not": [...]   // 必须不匹配(NOT)       │   │
│  │      }                                                │   │
│  │    }                                                  │   │
│  │  }                                                    │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  四个子句的评分行为:                                       │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  子句       匹配要求      影响评分      缓存行为     │   │
│  │  ─────────────────────────────────────────────────   │   │
│  │  must       必须匹配      影响_score    不缓存       │   │
│  │  filter     必须匹配      不影响_score   缓存!       │   │
│  │  should     可选匹配      匹配的越多    不缓存       │   │
│  │                           分数越高                   │   │
│  │  must_not   必须不匹配    不影响_score    缓存!       │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  关键规则:如果 bool 中没有 must/filter,                  │
│            should 中至少一个必须匹配                        │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

3.2 bool 查询实战:电商搜索 ​

┌─────────────────────────────────────────────────────────────┐
│                    电商搜索完整 bool 查询                     │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  {                                                          │
│    "query": {                                               │
│      "bool": {                                              │
│        "must": [                         // 必须匹配         │
│          {                                                    │
│            "multi_match": {                                  │
│              "query": "小米手机",                             │
│              "fields": ["title^3", "description^1.5",        │
│                         "brand^2"],                          │
│              "type": "best_fields"                           │
│            }                                                  │
│          }                                                    │
│        ],                                                     │
│        "filter": [                       // 硬过滤(不评分)  │
│          {"term": {"status": "active"}},                     │
│          {"range": {"price": {"gte": 1000, "lte": 5000}}},  │
│          {"term": {"category": "phone"}}                     │
│        ],                                                     │
│        "should": [                       // 加分项           │
│          {"term": {"has_discount": true}},                   │
│          {"term": {"free_shipping": true}},                  │
│          {"range": {"rating": {"gte": 4.5}}}                 │
│        ],                                                     │
│        "must_not": [                     // 排除项           │
│          {"term": {"condition": "used"}}                     │
│        ]                                                      │
│      }                                                        │
│    },                                                         │
│    "sort": [                            // 排序               │
│      {"_score": "desc"},                                    │
│      {"sales_count": "desc"}                                │
│    ]                                                          │
│  }                                                            │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

3.3 dis_max 与 function_score ​

┌─────────────────────────────────────────────────────────────┐
│                dis_max 与 function_score                     │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  dis_max:取最佳匹配子句的分数(而非求和)                  │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  {                                                    │   │
│  │    "dis_max": {                                       │   │
│  │      "queries": [                                     │   │
│  │        {"match": {"title": "小米手机"}},              │   │
│  │        {"match": {"description": "小米手机"}}         │   │
│  │      ],                                               │   │
│  │      "tie_breaker": 0.3   // 次佳分数 × 0.3 加进来  │   │
│  │    }                                                  │   │
│  │  }                                                    │   │
│  │  final_score = max_score + tie_breaker × other_scores │   │
│  │                                                       │   │
│  │  适用:同一个内容出现在多个字段时,不希望重复加分      │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  function_score:自定义评分公式                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  {                                                    │   │
│  │    "function_score": {                                │   │
│  │      "query": {"match": {"title": "小米手机"}},       │   │
│  │      "functions": [                                   │   │
│  │        {                                              │   │
│  │          "field_value_factor": {    // 字段值因子       │   │
│  │            "field": "sales_count",                    │   │
│  │            "factor": 1.2,            // 销量×1.2      │   │
│  │            "modifier": "log1p"       // 用 log 平滑   │   │
│  │          }                                            │   │
│  │        },                                             │   │
│  │        {                                              │   │
│  │          "gauss": {                  // 衰减函数       │   │
│  │            "created_at": {                            │   │
│  │              "origin": "now",        // 新商品加分     │   │
│  │              "scale": "30d",         // 30天后衰减     │   │
│  │              "decay": 0.5            // 衰减50%        │   │
│  │            }                                          │   │
│  │          }                                            │   │
│  │        }                                              │   │
│  │      ],                                               │   │
│  │      "score_mode": "multiply"   // 函数之间相乘       │   │
│  │    }                                                  │   │
│  │  }                                                    │   │
│  │  最终: BM25得分 × 销量因子 × 新鲜度因子                │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

第4部分:聚合(Aggregations) ​

4.1 聚合三大类型 ​

┌─────────────────────────────────────────────────────────────┐
│                    聚合三大类型全景                           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  Bucket Aggregation(分桶聚合)                       │   │
│  │  ┌──────────────────────────────────────────────┐   │   │
│  │  │  把文档分成多个"桶"                             │   │
│  │  │                                              │   │
│  │  │  terms: "category" → {phone: 150, laptop: 80} │   │
│  │  │  range: "price" → {0-1000: 30, ...}           │   │
│  │  │  date_histogram: "created_at" → 按月分桶      │   │
│  │  │  filter: 只聚合满足条件的文档                  │   │
│  │  └──────────────────────────────────────────────┘   │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  Metrics Aggregation(指标聚合)                      │   │
│  │  ┌──────────────────────────────────────────────┐   │   │
│  │  │  对桶内文档计算统计指标                        │   │
│  │  │                                              │   │
│  │  │  avg: 平均价格 → 3267.50                     │   │
│  │  │  sum: 总销量   → 12345                       │   │
│  │  │  min/max: 最低/最高价格                       │   │
│  │  │  stats: 一次性返回 count/min/max/avg/sum      │   │
│  │  │  cardinality: 近似去重计数(UV 等场景)       │   │
│  │  └──────────────────────────────────────────────┘   │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  Pipeline Aggregation(管道聚合)                    │   │
│  │  ┌──────────────────────────────────────────────┐   │   │
│  │  │  对聚合结果再做聚合                            │   │
│  │  │                                              │   │
│  │  │  derivative: 环比增长(本月 vs 上月)         │   │
│  │  │  moving_avg: 移动平均(平滑趋势线)           │   │
│  │  │  cumulative_sum: 累计求和(累计到当前的销量)  │   │
│  │  │  bucket_script: 自定义计算(利润率 = 利润/收入)│   │
│  │  └──────────────────────────────────────────────┘   │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

4.2 聚合实战:商品搜索面板 ​

┌─────────────────────────────────────────────────────────────┐
│                    商品搜索 + Facet 聚合                      │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  搜索"手机"时,同时返回:                                   │
│  • 品牌分布(facet)                                        │
│  • 价格区间                                                │
│  • 各分类下的平均价格                                       │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  GET /products/_search                                │   │
│  │  {                                                    │   │
│  │    "query": {"match": {"title": "手机"}},             │   │
│  │    "size": 0,                      // 不返回文档      │   │
│  │    "aggs": {                                          │   │
│  │      "brands": {                   // 品牌分布        │   │
│  │        "terms": {"field": "brand.keyword",            │   │
│  │                  "size": 10}                          │   │
│  │      },                                               │   │
│  │      "price_ranges": {             // 价格区间        │   │
│  │        "range": {                                     │   │
│  │          "field": "price",                            │   │
│  │          "ranges": [                                  │   │
│  │            {"to": 1000},                              │   │
│  │            {"from": 1000, "to": 3000},                │   │
│  │            {"from": 3000, "to": 5000},                │   │
│  │            {"from": 5000}                             │   │
│  │          ]                                            │   │
│  │        }                                              │   │
│  │      },                                               │   │
│  │      "avg_price_by_brand": {       // 嵌套聚合        │   │
│  │        "terms": {"field": "brand.keyword"},           │   │
│  │        "aggs": {                                      │   │
│  │          "avg_price": {"avg": {"field": "price"}}     │   │
│  │        }                                              │   │
│  │      }                                                │   │
│  │    }                                                  │   │
│  │  }                                                    │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

4.3 terms 聚合的准确性问题 ​

┌─────────────────────────────────────────────────────────────┐
│                terms 聚合的近似准确性问题                     │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  terms 聚合默认是近似的(基于每个 shard 的 top N)——       │
│  分片数越多,准确度越低                                     │
│                                                             │
│  场景:3 个 shard,每个 shard 返回 top 3 品牌              │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  Shard 0: [华为:50, 苹果:45, 小米:40]               │   │
│  │  Shard 1: [华为:48, 三星:30, 小米:28]               │   │
│  │  Shard 2: [苹果:55, OPPO:20, 小米:18]               │   │
│  │                                                      │   │
│  │  汇总(coordinating node 只看到 top 3×3=9条):       │   │
│  │  华为: 98, 苹果: 100, ...                            │   │
│  │                                                      │   │
│  │  问题:vivo 在 Shard 1 有 29 个文档(排第4),       │   │
│  │        但 Shard 2 只有 5 个(排第20)                │   │
│  │        vivo 在 Shard 1 被截断,汇总时丢失!          │   │
│  │        实际总量 vivo: 34 > 三星: 30                  │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  解决方式:                                                 │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  1. shard_size 设大(默认 size×1.5+10,可手动调大)  │   │
│  │  2. 如果 accuracy 至关重要,数据量不大时:            │   │
│  │     {"terms": {"field": "brand",                     │   │
│  │                "shard_size": 10000}}                 │   │
│  │  3. 设置 index 只有 1 个主分片(牺牲扩展性换准确度) │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

第5部分:相关性调优 ​

5.1 BM25 参数调优 ​

┌─────────────────────────────────────────────────────────────┐
│                    BM25 参数调优                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  评分公式:                                                 │
│  Score(D,Q) = Σ IDF(qi) × (f(qi,D) × (k1 + 1))            │
│                             / (f(qi,D) + k1 × (1 - b +      │
│                                b × |D| / avgdl))           │
│                                                             │
│  两个关键参数:                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                                                      │   │
│  │  k1 (默认 1.2):词频饱和度控制                        │   │
│  │  ┌──────────────────────────────────────────────┐   │   │
│  │  │                                              │   │   │
│  │  │  k1 越大 → 词频的影响越大                     │   │   │
│  │  │  k1 越小 → 词频更快饱和                       │   │   │
│  │  │                                              │   │   │
│  │  │  例子:                                       │   │   │
│  │  │  文档A: "手机" 出现 1 次                      │   │   │
│  │  │  文档B: "手机" 出现 10 次                     │   │   │
│  │  │                                              │   │   │
│  │  │  k1=1.2: B 得分 ≈ A×3                        │   │   │
│  │  │  k1=0.5: B 得分 ≈ A×1.8  (差距缩小)          │   │   │
│  │  │  k1=3.0: B 得分 ≈ A×5    (差距拉大)          │   │   │
│  │  └──────────────────────────────────────────────┘   │   │
│  │                                                      │   │
│  │  b (默认 0.75):文档长度归一化程度                    │   │
│  │  ┌──────────────────────────────────────────────┐   │   │
│  │  │                                              │   │   │
│  │  │  b=0   → 不考虑文档长度(长文档不受惩罚)     │   │   │
│  │  │  b=1   → 完全按文档长度归一化(长文档严重惩罚)│   │   │
│  │  │  b=0.75 → 折中(默认值)                      │   │   │
│  │  │                                              │   │   │
│  │  │  适用:                                       │   │   │
│  │  │  短文档(tweet、标题)→ b 可以小一些          │   │   │
│  │  │  长文档(文章、书籍)→ b 接近默认值           │   │   │
│  │  └──────────────────────────────────────────────┘   │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

5.2 字段权重与 boosting ​

┌─────────────────────────────────────────────────────────────┐
│                    权重设计策略                               │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  权重决定"哪个字段的匹配更重要":                            │
│                                                             │
│  索引时权重(不推荐):                                     │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  "title": {"type": "text", "boost": 3}               │   │
│  │  问题:权重写死在 mapping 里,改权重需要 reindex      │   │
│  │        ES 7.x+ 已废弃索引时 boost                     │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  查询时权重(推荐):                                       │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  "fields": ["title^3", "brand^2", "description^1"]   │   │
│  │  ^ 后接的数值表示权重倍数                             │   │
│  │                                                      │   │
│  │  经验值:                                             │   │
│  │  • title: 3-5(标题是最强信号)                      │   │
│  │  • brand/tags: 2-3(品牌标签次之)                   │   │
│  │  • description: 1-2(内容权重最低)                  │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  权重设计原则:                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  1. 字段越短,权重应该越高                            │   │
│  │     → 短字段匹配 = 高信号,长字段匹配 = 噪声         │   │
│  │  2. 字段离用户意图越近,权重应该越高                  │   │
│  │     → 标题 > 摘要 > 正文                              │   │
│  │  3. A/B 测试决定最终权重——没有万能公式                │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

第6部分:常见查询模式 ​

6.1 自动补全(Autocomplete) ​

┌─────────────────────────────────────────────────────────────┐
│                    自动补全三种方案                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  方案1:Completion Suggester(最快)                        │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  Mapping:                                             │   │
│  │  "suggest": {"type": "completion"}                   │   │
│  │                                                      │   │
│  │  查询:                                                │   │
│  │  {"suggest": {"title-suggest": {                     │   │
│  │     "prefix": "小米",                                │   │
│  │     "completion": {"field": "suggest"}               │   │
│  │  }}}                                                  │   │
│  │                                                      │   │
│  │  特点:基于 FST,毫秒级响应                           │   │
│  │  限制:只能前缀匹配,不支持中间匹配                    │   │
│  │  适用:搜索框实时补全 (Search-as-you-type)            │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  方案2:Edge N-Gram Tokenizer(灵活)                      │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  "小米手机" → 小, 小米, 小米手, 小米手机            │   │
│  │  搜索"小米" → 匹配"小米" token → 命中               │   │
│  │                                                      │   │
│  │  特点:用标准 match 查询,灵活性高                    │   │
│  │  限制:索引体积膨胀明显                               │   │
│  │  适用:对补全质量要求高、需要过滤/排序的场景          │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  方案3:Search-as-you-type(中间匹配)                      │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  Mapping: "title": {"type": "search_as_you_type"}    │   │
│  │  查询: {"multi_match": {"query": "小米",             │   │
│  │                         "type": "bool_prefix"}}       │   │
│  │                                                      │   │
│  │  支持:前缀+中间匹配+多字段                           │   │
│  │  适用:ES 7.x+,兼顾速度和灵活性                     │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

6.2 模糊搜索与纠错 ​

┌─────────────────────────────────────────────────────────────┐
│                    模糊搜索实现方案                           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  场景:用户输入 "ipone",想找 "iPhone"                      │
│                                                             │
│  方案1:Fuzzy Query(编辑距离)                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  {"fuzzy": {"title": {"value": "ipone",              │   │
│  │                       "fuzziness": "AUTO"}}}         │   │
│  │                                                      │   │
│  │  fuzziness 规则:                                     │   │
│  │  • 0-2 字符:必须完全匹配                             │   │
│  │  • 3-5 字符:允许 1 个编辑距离                        │   │
│  │  • >5 字符:允许 2 个编辑距离                         │   │
│  │                                                      │   │
│  │  编辑距离 = 增/删/改一个字符的次数                    │   │
│  │  "ipone" → "iphone": 1次操作(插入h) → 可匹配       │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  方案2:同义词 + 拼音搜索(中文场景)                       │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  同义词过滤器:                                       │   │
│  │  "小米, xiaomi, 粗粮手机" → 全映射为"小米"           │   │
│  │                                                      │   │
│  │  拼音分析器:                                         │   │
│  │  "小米" → [xiao, mi]                                │   │
│  │  用户输入拼音 "xiaomi" → 也能搜到"小米"              │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  方案3:混合策略(推荐)                                    │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  1. 先用精确 match 查询(快速)                       │   │
│  │  2. 如果结果太少(< 5条),自动 fallback:            │   │
│  │     a. fuzzy query(拼写纠错)                        │   │
│  │     b. 同义词扩展                                      │   │
│  │     c. 拼音匹配                                       │   │
│  │  3. 前端展示"您是不是要找:iPhone?"                  │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

第7部分:查询性能优化 ​

7.1 Profile API —— 查询性能诊断 ​

┌─────────────────────────────────────────────────────────────┐
│                    Profile API 使用                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  在查询中加 "profile": true 可以获得详细的性能分解:       │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  {                                                    │   │
│  │    "profile": true,                                   │   │
│  │    "query": { ... }                                   │   │
│  │  }                                                    │   │
│  │                                                       │   │
│  │  输出:                                               │   │
│  │  {                                                    │   │
│  │    "profile": {                                       │   │
│  │      "shards": [{                                     │   │
│  │        "id": "[xxx][0]",                              │   │
│  │        "searches": [{                                 │   │
│  │          "query": [{                                  │   │
│  │            "type": "BooleanQuery",                    │   │
│  │            "description": "title:小米 title:手机",    │   │
│  │            "time_in_nanos": 1523400,                  │   │
│  │            "breakdown": {                             │   │
│  │              "create_weight": 23400,                  │   │
│  │              "build_scorer": 890000,   ← 慢在这里!   │   │
│  │              "next_doc": 580000,         ← 也慢      │   │
│  │              "advance": 0,                            │   │
│  │              "score": 30000                           │   │
│  │            }                                          │   │
│  │          }]                                           │   │
│  │        }]                                             │   │
│  │      }]                                               │   │
│  │    }                                                  │   │
│  │  }                                                    │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  breakdown 字段含义:                                       │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  create_weight → 构建查询权重的时间                   │   │
│  │  build_scorer  → 构建评分器(读取倒排表最耗时)      │   │
│  │  next_doc      → 遍历匹配文档的时间                   │   │
│  │  advance       → 跳表跳跃的时间                       │   │
│  │  score         → 计算评分的时间                       │   │
│  │                                                      │   │
│  │  build_scorer 慢 → 倒排表太大,考虑分词优化          │   │
│  │  next_doc 慢     → 匹配文档太多,加 filter 缩小范围  │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

7.2 Filter 缓存与 Routing ​

┌─────────────────────────────────────────────────────────────┐
│                查询性能优化三板斧                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  优化1:善用 Filter Context(最重要)                       │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  把不需要评分的条件放进 filter,而不是 must           │   │
│  │  filter 结果自动缓存(LRU,默认缓存 10% heap)        │   │
│  │                                                      │   │
│  │  缓存效果验证:                                       │   │
│  │  GET /_stats/query_cache?human                       │   │
│  │  → cache_size, evictions, hit_count, miss_count      │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  优化2:Routing —— 精准定位 shard                         │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  默认:查询广播到所有 shard,每个 shard 都要搜        │   │
│  │  使用 routing:根据某个字段值路由到特定 shard         │   │
│  │                                                      │   │
│  │  场景:按 userId 搜索订单                             │   │
│  │  PUT /orders/_doc/123?routing=user_456               │   │
│  │  GET /orders/_search?routing=user_456                │   │
│  │                                                      │   │
│  │  代价:单 shard 查询,延迟从 50ms → 5ms              │   │
│  │  限制:查询必须包含 routing 值,否则搜不到            │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  优化3:限制搜索范围                                        │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  • 使用 index pattern 限制搜索的索引                 │   │
│  │  • 用 filter 先缩小文档范围(时间范围等)            │   │
│  │  • 设置 terminate_after 限制扫描文档数               │   │
│  │  • 设置 timeout 防止慢查询拖垮集群                   │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

7.3 慢查询日志与分析 ​

┌─────────────────────────────────────────────────────────────┐
│                    慢查询日志配置                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  配置慢查询阈值:                                           │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  PUT /_cluster/settings                               │   │
│  │  {                                                    │   │
│  │    "transient": {                                     │   │
│  │      "index.search.slowlog.threshold.query.warn":     │   │
│  │                                       "500ms",        │   │
│  │      "index.search.slowlog.threshold.query.info":     │   │
│  │                                       "200ms",        │   │
│  │      "index.search.slowlog.level": "info"             │   │
│  │    }                                                  │   │
│  │  }                                                    │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  慢查询日志输出示例:                                       │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  [2024-01-15T10:23:45,123][INFO ][index.search.slowlog│   │
│  │   query] [node-1] [products/0]                       │   │
│  │   took[850.5ms], took_millis[850],                   │   │
│  │   total_hits[12345],                                 │   │
│  │   source[{"query":{"match":{"title":"手机"}}}]       │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  慢查询常见原因与对策:                                     │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  原因                   对策                         │   │
│  │  ───────────────────────────────────────────────     │   │
│  │  match 高基数字段      加 filter 缩小范围            │   │
│  │  wildcard 前导通配     改用 ngram 或 edge ngram      │   │
│  │  深度分页 (from > 1万)  改用 search_after            │   │
│  │  大聚合 (cardinality)   用预计算或 approximate       │   │
│  │  脚本评分              改用索引时预计算字段           │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

核心总结 ​

总结1:Query vs Filter ​

Query Context (must/should)  → 评分、不缓存、用于全文匹配
Filter Context (filter)    → 不评分、自动缓存、用于精确筛选

原则:全文匹配用 Query,精确筛选用 Filter
1
2
3
4

总结2:bool 查询四子句 ​

子句必须匹配评分缓存
must是影响否
filter是不影响是
should否(无must时是)匹配越多分越高否
must_not必须不匹配不影响是

总结3:相关性调优层次 ​

Layer 0: 正确使用 Query vs Filter(基础)
Layer 1: multi_match + 字段权重(^3, ^2, ^1)
Layer 2: function_score(销量、新鲜度等因素)
Layer 3: 自定义 BM25 参数(k1, b)
Layer 4: script_score(自定义评分逻辑)
1
2
3
4
5

总结4:聚合三大类型 ​

Bucket → 分桶(terms, range, date_histogram)
Metrics → 桶内统计(avg, sum, min/max, stats, cardinality)
Pipeline → 聚合的聚合(derivative, moving_avg, cumulative_sum)
1
2
3

章节测试 ​

测试1:Query vs Filter ​

以下查询中,哪个应该放在 filter 里,哪个应该放在 must 里? A. 标题包含"小米" B. 价格在 1000-5000 C. 商品状态为"上架" D. 描述包含"性价比"

测试2:multi_match ​

best_fields、most_fields、cross_fields 三种模式分别适用于什么场景?

测试3:bool 查询 ​

在没有 must 子句的情况下,should 子句的行为是什么?

测试4:聚合 ​

terms 聚合为什么默认不准确?如何提高准确度?

测试5:相关性 ​

文档 A 标题"小米手机"、描述"一部好用的智能手机"; 文档 B 标题"智能手机推荐"、描述"小米、华为、苹果等品牌手机对比"。 搜索"小米手机"时,BM25 会给哪个文档更高分?为什么?

测试6:性能 ​

用户抱怨搜索越来越慢,你应该按什么顺序排查?

测试7:综合设计 ​

设计一个电商搜索接口,支持:关键词搜索、品牌筛选、价格区间、按销量+相关性排序、搜索词自动补全、拼写纠错。写出核心的 ES DSL 结构和 mapping 设计要点。


参考答案 ​

测试1答案 ​

答案:

  • A(标题包含"小米")→ must(全文匹配,需要评分)
  • B(价格范围)→ filter(精确筛选,不需要评分,可缓存)
  • C(商品状态)→ filter(精确筛选,可缓存)
  • D(描述包含"性价比")→ should(可选加分项,匹配更好但非必须)

测试2答案 ​

答案:

  • best_fields:搜索词集中在单个字段最佳时(如"小米13Pro" → title 完整匹配)
  • most_fields:同一内容出现在多个字段时(如 title 和 description 都包含"小米")
  • cross_fields:搜索词分散在不同字段时(如"张三 北京" → name 和 address 各含一词)

测试3答案 ​

答案:如果 bool 查询中既没有 must 也没有 filter,则 should 中至少一条必须匹配(变为 required)。即 "(must 为空) → should 变为必须至少匹配一个"。

如果 bool 中已有 must 或 filter,则 should 中的条件匹配越多得分越高,但不强制匹配。


测试4答案 ​

答案:terms 聚合在每个 shard 上独立计算 top N,然后由协调节点汇总。如果某个 term 在某些 shard 排名靠后(被截断),汇总时会丢失数据。提高准确度:增大 shard_size 参数、减少分片数(如 1 个主分片)、或使用 composite aggregation 分页遍历所有桶。


测试5答案 ​

答案:文档 A 分数更高。理由:

  • 文档 A 标题"小米手机"是完整的精确匹配(两个词连续出现在短字段中)
  • 文档 A 描述也包含"手机",形成跨字段加分
  • BM25 的 IDF 会给"小米"这个词较高的权重(相比"手机"更稀有)
  • 文档长度归一化(b=0.75)使得短文档占优
  • 文档 B 虽然标题包含"手机"、描述包含"小米",但它们分散在不同字段和较长的文本中

测试6答案 ​

答案:

  1. 慢查询日志 → 找到最慢的查询
  2. Profile API → 定位慢在哪个阶段(build_scorer / next_doc / score)
  3. 检查是否滥用 wildcard / leading wildcard
  4. 检查 query context vs filter context 是否正确使用
  5. 检查深度分页(from 是否过大)
  6. 检查聚合是否使用了高基数 cardinality
  7. 检查 filter cache 命中率
  8. 检查 shard 数量和集群健康状态

测试7答案 ​

答案:

核心 mapping 要点:

json
{
  "title": {
    "type": "text", "analyzer": "ik_max_word",
    "fields": {
      "keyword": {"type": "keyword"},
      "completion": {"type": "completion"},
      "edge_ngram": {"type": "text", "analyzer": "edge_ngram_analyzer"}
    }
  },
  "brand": {"type": "keyword"},
  "price": {"type": "float"},
  "sales_count": {"type": "integer"},
  "status": {"type": "keyword"}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

核心查询 DSL:

json
{
  "query": {
    "bool": {
      "must": [{"multi_match": {"query": "小米", "fields": ["title^3","description^1.5"]}}],
      "filter": [
        {"terms": {"brand.keyword": ["小米","华为"]}},
        {"range": {"price": {"gte":1000,"lte":5000}}},
        {"term": {"status": "active"}}
      ]
    }
  },
  "sort": [{"_score":"desc"},{"sales_count":"desc"}]
}
1
2
3
4
5
6
7
8
9
10
11
12
13

补全和纠错用独立的 suggest API 和 fuzzy 查询,作为独立的接口路径。


相关笔记 ​

  • [[./00-overview]] - 搜索引擎概览
  • [[./03-elasticsearch-cluster]] - ES 集群规划与运维
  • [[/03-web/07-middleware/06-elasticsearch]] - ES 倒排索引深入

下一步学习 ​

  • [ ] 阅读 03 - Elasticsearch 集群规划与运维
  • [ ] 阅读 04 - Meilisearch 与替代方案

学习状态:🟡 开始学习

最后更新于:

Pager
上一篇2. Elasticsearch——为什么 Like 查询总是那么慢 / Elasticsearch for Full-Text Search at Scale
下一篇4. Elasticsearch 集群规划与运维——为什么你的集群总是"黄" / Elasticsearch Cluster Planning and Operations

持续记录,持续成长

Copyright © Tidenflow