https://artifacts.elastic.co/releases/stack.json
https://artifacts.elastic.co/downloads/8.17.4.json
https://www.elastic.co/downloads/past-releases
索引别名(Aliases)
索引别名是 Elasticsearch 中指向一个或多个索引的逻辑名称。类似于数据库中的视图或快捷方式,它允许用户通过别名操作索引数据,而无需直接引用物理索引名称。
基本用法
- 创建别名
- 切换别名
- 删除别名
- 查询别名
- 别名指向多个索引
- 别名过滤数据
- 别名路由优化
使用场景
1. 抽象化索引名称:解耦应用层与物理索引结构。
1 | // 创建别名并绑定到索引 |
2.零停机维护:通过切换别名实现索引重建或迁移,无需停服。
1 | // 1. 创建新索引 |
3.读写分离:区分写入和读取的索引目标。
1 | // 定义写别名(指向单一索引) |
4.数据过滤与路由:为别名附加过滤条件或路由规则,优化查询性能。
- 过滤条件(Filter):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// 创建别名时附加过滤条件(仅返回 status=active 的文档)
POST /_aliases
{
"actions": [
{
"add": {
"index": "user_data",
"alias": "active_users",
"filter": { // 过滤条件
"term": { "status": "active" }
}
}
}
]
}
// 查询时自动应用过滤
GET /active_users/_search - 路由规则(Routing):
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// 创建别名时指定路由规则
POST /_aliases
{
"actions": [
{
"add": {
"index": "orders",
"alias": "orders_by_user",
"routing": "user_id" // 按 user_id 路由分片
}
}
]
}
// 写入时指定路由值(自动路由到对应分片)
POST /orders_by_user/_doc?routing=123
{
"user_id": 123,
"product": "Laptop"
}
// 查询时强制路由(提升性能)
GET /orders_by_user/_search?routing=123
{
"query": { "term": { "user_id": 123 }}
}
索引设置(Index Settings)
用于配置索引的运行参数,例如分片数量、刷新间隔、缓存策略、合并策略、事务日志等。它主要关注的是索引的性能、存储、分布式特性等底层参数,与数据内容无关。
1. 分片与分配相关
- number_of_shards:主分片数,决定数据分片方式,创建后不可更改。
- number_of_replicas:副本分片数,影响查询性能和高可用,可动态调整。
- index.routing.allocation:控制分片分配到特定节点。动态调整分副本分片数量
1
2
3
4
5
6
7
8PUT /my_index
{
"settings": {
"index.number_of_shards": 3, // 主分片数
"index.number_of_replicas": 2, // 副本分片数
"index.routing.allocation.include._tag": "hot" // 分配到特定标签节点
}
}1
2
3
4PUT /my_index/_settings
{
"index.number_of_replicas": 1
}
2. 性能与写入相关
- refresh_interval:控制数据刷新频率,影响新写入数据何时可被搜索。
- translog:事务日志设置,控制数据持久性。
- merge:段合并策略,优化存储和查询性能。禁用刷新以提升写入性能:
1
2
3
4
5
6
7
8
9
10PUT /my_index
{
"settings": {
"index.refresh_interval": "30s", // 每30秒刷新
"index.translog.durability": "async", // 异步持久化
"index.translog.sync_interval": "5s", // 事务日志同步间隔
"index.translog.flush_threshold_size": "512mb", //设置触发 translog 刷新的大小阈值。
"index.merge.policy.max_merge_at_once": 10 // 最大合并段数
}
}1
2
3
4PUT /my_index/_settings
{
"index.refresh_interval": "-1"
}
3. 分析器与搜索相关
- analysis:定义分词器、过滤器等,影响字段的索引和查询方式。
- analyzer: 自定义分析器,通常由分词器和过滤器构成,用于文本预处理。
- tokenizer 与 token filters:
- 使用
standard分词器实现基本分词; - 配置
lowercase过滤器进行小写转换,以及stop过滤器进行停用词过滤; char_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
29PUT my-analysis-index
{
"settings": {
"analysis": {
"analyzer": { // 定义分析器
"my_custom_analyzer": {
"type": "custom",
"tokenizer": "standard", // 使用标准分词器
"char_filter": [ // 使用字符过滤器
"html_strip" // 移除HTML标签
],
"filter": [ // 使用词元过滤器
"lowercase", // 转小写
"stop" // 移除停用词
]
}
},
// 可以继续定义 tokenizer, char_filter, filter 等
}
},
"mappings": {
"properties": {
"my_text_field": {
"type": "text",
"analyzer": "my_custom_analyzer" // 字段使用上面定义的分析器
}
}
}
}
4. 生命周期管理相关
索引生命周期管理(ILM)用于自动管理索引的阶段性操作。
- index.lifecycle.name:关联 ILM 策略,控制索引滚动、删除等。
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// 定义 ILM 策略
PUT /_ilm/policy/my_policy
{
"policy": {
"phases": {
"hot": {
"actions": {
"rollover": {
"max_size": "50gb",
"max_age": "30d"
}
}
},
"delete": {
"min_age": "90d",
"actions": {
"delete": {}
}
}
}
}
}
// 应用到索引
PUT /my_index
{
"settings": {
"index.lifecycle.name": "my_policy"
}
}
5.其他核心设置
- index.blocks:控制索引的读写权限。
- index.priority:设置索引恢复优先级。
- index.max_result_window:控制
from+size的最大值,即通过分页(from,size)可以获取的最大文档数量。默认是10000。 - index.mapping.total_fields.limit:限制一个索引中可以包含的最大字段数量(包括嵌套字段、对象字段等)。默认是
1000。1
2
3
4
5
6
7PUT /my_index/_settings
{
"index.blocks.read_only": true, // 设置只读
"index.priority": 10, // 高优先级恢复
"index.max_result_window": 20000, // 提高窗口上限到20000
"index.mapping.total_fields.limit": 1500 // 提高字段数量上限
}
6.完整的settings
1 | PUT /example_index |
映射(Mapping)
用于定义数据结构和字段属性,主要关注文档中数据如何存储、分析和查询。mappings 决定了字段的类型、分析方式、格式化规则等,它直接影响查询结果的准确性和搜索行为。
- Mapping:类似数据库的 Schema,定义索引中每个字段的 数据类型、分词规则、索引方式等。
- Dynamic Mapping:自动推断字段类型(如未手动定义 Mapping,Elasticsearch 会根据写入的数据自动创建字段类型)。
- Explicit Mapping:手动明确定义字段类型和规则。
字段类型(Field Types)
1. 核心字段类型(Core Data Types)
| 类型名称 | 描述 | 适用场景 | 示例 |
|---|---|---|---|
text |
全文检索字段,默认会被分词 | 需要分词搜索的文本(如文章内容、日志) | "content": { "type": "text" } |
keyword |
精确值字段,不分词 | 精确匹配、聚合、排序(如状态码、标签) | "status": { "type": "keyword" } |
long |
64位有符号整数 | 大范围整数(如订单ID) | "id": { "type": "long" } |
integer |
32位有符号整数 | 中等范围整数(如年龄、数量) | "age": { "type": "integer" } |
short |
16位有符号整数 | 小范围整数(如状态码) | "error_code": { "type": "short" } |
byte |
8位有符号整数 | 极小范围整数(如开关状态) | "flag": { "type": "byte" } |
double |
64位双精度浮点数 | 高精度数值(如科学计算) | "price": { "type": "double" } |
float |
32位单精度浮点数 | 常规精度数值(如评分) | "rating": { "type": "float" } |
boolean |
布尔值(true/false) |
逻辑判断字段 | "is_active": { "type": "boolean" } |
date |
日期类型(需指定格式) | 时间戳、日期范围查询 | "created_at": { "type": "date", "format": "yyyy-MM-dd" } |
binary |
二进制数据(Base64编码) | 存储加密数据或二进制文件 | "file": { "type": "binary" } |
2. 复杂类型(Complex Data Types)
| 类型名称 | 描述 | 适用场景 | 示例 |
|---|---|---|---|
object |
嵌套的 JSON 对象 | 结构化数据(如用户信息对象) | "author": { "type": "object", "properties": { ... } } |
nested |
独立存储的嵌套对象数组(解决对象数组扁平化问题) | 多对一关系数据(如评论列表) | "comments": { "type": "nested", "properties": { ... } } |
flattened |
将嵌套字段扁平化为关键字 | 处理未知或动态嵌套字段(避免映射爆炸) | "metadata": { "type": "flattened" } |
join |
定义父子文档关系 | 一对多关系(如博客与评论) | "relation": { "type": "join", "relations": { "parent": "child" } } |
3. 地理位置类型(Geo Data Types)
| 类型名称 | 描述 | 适用场景 | 示例 |
|---|---|---|---|
geo_point |
经纬度坐标点 | 地理位置搜索(如附近的人) | "location": { "type": "geo_point" } |
geo_shape |
复杂地理形状(多边形、线等) | 地理围栏、区域覆盖分析 | "area": { "type": "geo_shape" } |
4. 特殊类型(Specialized Data Types)
| 类型名称 | 描述 | 适用场景 | 示例 |
|---|---|---|---|
ip |
IPv4/IPv6 地址 | 分析网络日志中的 IP | "client_ip": { "type": "ip" } |
completion |
自动补全建议字段 | 搜索建议功能(如输入提示) | "suggest": { "type": "completion" } |
token_count |
统计文本字段的分词数量 | 分析文本长度(如统计文章字数) | "word_count": { "type": "token_count", "analyzer": "standard" } |
percolator |
存储查询条件,用于反向匹配文档 | 订阅特定条件的文档(如预警系统) | "query": { "type": "percolator" } |
alias |
字段别名(指向实际字段的虚拟字段) | 简化复杂查询中的字段引用 | "user": { "type": "alias", "path": "user.name" } |
histogram |
预聚合直方图数据(如数值分布) | 存储预计算的直方图数据(提升聚合性能) | "price_histogram": { "type": "histogram" } |
constant_keyword |
所有文档中值相同的 keyword 类型 |
固定分类标识(如日志来源) | "env": { "type": "constant_keyword", "value": "production" } |
5. 范围类型(Range Data Types)
| 类型名称 | 描述 | 适用场景 | 示例 |
|---|---|---|---|
integer_range |
整数范围(如 10-20) |
时间段、年龄范围 | "age_range": { "type": "integer_range" } |
float_range |
浮点数范围 | 价格区间、温度范围 | "price_range": { "type": "float_range" } |
long_range |
长整数范围 | ID 范围、大数值区间 | "id_range": { "type": "long_range" } |
double_range |
双精度浮点数范围 | 高精度数值区间 | "score_range": { "type": "double_range" } |
date_range |
日期范围 | 时间段查询(如活动有效期) | "event_period": { "type": "date_range", "format": "yyyy-MM-dd" } |
ip_range |
IP 地址范围(CIDR格式) | 网络 IP 段分析 | "ip_blocks": { "type": "ip_range" } |
6. 其他类型(Others)
| 类型名称 | 描述 | 适用场景 | 示例 |
|---|---|---|---|
wildcard |
高性能通配符搜索的 keyword 类型(ES 7.9+) |
日志中的模糊匹配(如 *error*) |
"log_message": { "type": "wildcard" } |
annotated-text |
支持注释的文本类型(需插件) | 包含元数据的文本分析 | "annotated": { "type": "annotated-text" } |
search_as_you_type |
支持逐字符搜索优化的文本类型(ES 7.9+) | 实时搜索建议(如即时搜索框) | "instant_search": { "type": "search_as_you_type" } |
1 | PUT /my_index |
动态映射(Dynamic Mapping)
Dynamic 参数
控制Elasticsearch是否自动推断新字段的类型并添加到映射中。它有三种模式:
true:自动推断新字段类型(默认)。false:忽略新字段(不索引、不存储)。strict:遇到新字段时抛出异常(严格模式,适合生产环境)。1
2
3
4
5
6{
"mappings": {
"dynamic": "strict", // 禁止自动添加字段
"properties": { ... }
}
}
dynamic_templates
允许用户自定义规则,动态映射新字段时根据条件(如字段名、数据类型)指定其类型和参数。每个模板包含以下部分:
- 名称:模板的唯一标识。
- 匹配条件:如
match(字段名匹配)、match_mapping_type(匹配Elasticsearch推断的类型)、path_match(嵌套字段路径匹配)。 - 映射规则:定义字段的最终类型和参数。
[!Note] 提示
- 模板按顺序匹配,第一个满足条件的模板生效。
- 若
dynamic设为false或strict,动态模板不会生效。
所有字符串字段设为text,并添加子字段keyword
1 | PUT my-index-000001/ |
特定前缀的字段设为text并分词
1 | { |
长数字字段映射为keyword
1 | { |
嵌套字段的特殊处理
1 | { |
索引选项(Indexing Options)
全局参数
enablecoerce
字段参数
- **
index**:是否索引字段(true/false)。禁用索引可节省存储,但无法搜索。 - **
doc_values**:是否启用列式存储(默认true,用于排序、聚合)。 - **
store**:是否独立存储原始值(默认false,仅在需要独立提取字段时启用)。 - **
analyzer**:定义全文检索字段的分词规则(如standard、ik_smart)。 - **
search_analyzer**:指定搜索时的分词器(默认与analyzer一致)。 - **
fields**:多字段特性(允许一个字段同时以不同方式索引,如text+keyword)。1
2
3
4
5
6
7
8
9
10{
"mappings": {
"properties": {
"log": {
"type": "text",
"index": false // 不索引,仅存储
}
}
}
}
1 | { |
元字段(Meta Fields)
_id:文档唯一标识。_source:存储原始 JSON 数据(禁用可节省空间,但无法直接获取原始数据)。_routing:自定义路由规则(控制文档存储到特定分片)。_all:已废弃,替代方案为copy_to字段。1
2
3
4
5
6
7{
"mappings": {
"_source": {
"enabled": false // 禁用原始数据存储
}
}
}
总结
Elasticsearch Mapping 的设计直接影响数据的 存储效率、查询性能 和 功能实现。核心关注点包括:
- 明确字段类型(如
textvskeyword)。 - 合理控制动态映射(
dynamic)。 - 优化分词规则(
analyzer和fields)。 - 利用高级特性(如
nested、copy_to、模板)。 - 对不搜索的字段设置
"index": false。 - 避免过度使用
nested类型(增加查询复杂度)。 - 对需聚合或排序的字段启用
doc_values(默认开启)。
索引模板(Index Template)
索引模板是一个预定义的“蓝图”,它规定了当一个新创建的索引名称与模板中定义的模式(index_patterns)匹配时,应该自动应用哪些设置(Settings)、映射(Mappings)和别名(Aliases)。
核心目的:
- 自动化: 自动配置新索引,无需每次手动指定。
- 一致性: 确保同类型的索引(如所有日志索引、所有指标索引)具有统一的结构和配置。
- 简化管理: 集中管理索引的通用配置。
基础模板
- 索引匹配模式(index_patterns) 定义模板作用的索引名称模式(例如
"log-*"表示所有以 log- 开头的索引)。 - 设置(settings) 如分片数、副本数、刷新间隔等。
- 映射(mappings) 定义字段的数据类型、分词器、动态模板等。
- 别名(aliases) 为新建索引自动配置别名,便于后续操作。
1 | PUT _index_template/my_template |
当你向一个不存在但名称匹配 "log-*" 的索引写入数据时,Elasticsearch 会自动根据此模板创建索引。
组件模板(Component Templates)
将可复用的配置模块化,多个组件模板可组合成一个索引模板。
1 | // 1. 创建组件模板(定义公共设置) |
动态模板(Dynamic Templates)
动态模板允许你针对符合特定条件的字段定义统一的映射规则,而不必对每个字段单独定义。比如,将所有自动检测为字符串的字段映射为 keyword 类型。
1 | PUT _index_template/dynamic_template_example |
此模板会使得所有索引名称匹配 "log1-*" 的索引中,自动映射的字符串字段都采用 text 类型,并添加子字段keyword便于精确匹配和聚合。
- match_mapping_type:
"string"表示匹配所有自动检测为字符串的字段。 - mapping:
"type": "text":默认将字段映射为 text 类型(用于全文检索)。"fields":为该字段添加子字段:- 子字段
"keyword"映射为 keyword 类型,常用于排序、聚合和精确匹配。
- 子字段
创建log1-20250414索引,并添加数据
1 | POST log1-20250414/_doc/1 |
GET log1-20250414/_mapping 后返回
1 | { |
分词器(Analyzer)
分词器(Analyzer)是 Elasticsearch 中用于将文本转换为可搜索词条(Tokens)的核心组件,作用于文档的索引和搜索阶段。它负责将原始文本(如句子、段落)拆解成有意义的词项,以便构建倒排索引,从而实现高效的全文检索。
分词器的组成
分词器由三个层级组件构成,按顺序处理文本:
- 字符过滤器(Character Filters)
处理原始文本的字符,例如移除HTML标签(html_strip)、替换特殊字符(如将&转为and)。 - 分词器(Tokenizer)
将文本切分为词条,例如按空格分割(whitespace)或按词语边界分割(standard)。 - 词条过滤器(Token Filters)
对分词后的词条进一步处理,如转小写(lowercase)、删除停用词(stop)、添加同义词(synonym)等。
字符过滤器(Character Filters)
分词器(Tokenizer)
词条过滤器(Token Filters)
自定义分词器
归一化器(Normalizer)
Normalizer只能用于 keyword 类型的字段,不能用于 text 字段。
Normalizer的组成
- Char Filters:(可选)先处理原始字符串(比如删掉某些字符)
- Token Filters:(必需)在字符级别继续处理,比如转小写、去除重音符号等。
Normalizer工作原理
当你把一个字符串存到带 Normalizer 的 keyword 字段时:
- 先用 char_filter 预处理原字符串(可选)。
- 然后用 filter 处理(比如小写化)。
- 最后存进去一整个处理好的字符串。
自定义normalizer
1 | PUT my_index |
其他
在linux上快速启动测试模式es单节点
用户准备
1
2adduser es
password es为用户添加sudo权限 在
/etc/sudoers添加1
es ALL=(ALL) ALL
下载elasticsearch
1
2
3
4
5
6
7mkdir /software
cd /software
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.17.4-linux-x86_64.tar.gz
tar -zxvf elasticsearch-8.17.4-linux-x86_64
chown -R es:es elasticsearch-8.17.4
su es ## 切换到es用户调整
elasticsearch.yml配置1
2
3
4network.host: 0.0.0.0
discovery.type: single-node
xpack.security.enabled: false
bootstrap.memory_lock: truejvm.options1
2
3
4-Xms512m
-Xmx512m
# 强制开启bootstrap checks
-Des.enforce.bootstrap.checks=true运行启动命令
1
2cd /software/elasticsearch-8.17.4
./bin/elasticsearch
下载配置kibana
1 | su root ##切换到root用户 |
1 | server.port: 5601 |
启动kibana
1 | cd .. |
[!Note] nohup
nohup是 Linux/Unix 系统中的一个命令,全称为 No Hang Up(不挂起)。它的作用是让程序在终端关闭(用户退出登录或断开连接)后依然保持运行,避免进程被系统终止(默认情况下,关闭终端会向相关进程发送SIGHUP信号,导致进程退出)。
1 >nohup <command> > nohup.out 2>&1 &
<command>是你需要运行的命令(如脚本、程序等)。&表示将命令放到后台运行,释放当前终端。> output.log:将标准输出重定向到output.log。2>&1:将标准错误也重定向到同一文件。
elasticsearch安装ik插件
https://github.com/infinilabs/analysis-ik
https://release.infinilabs.com/analysis-ik/stable/
1 | cd /software/elasticsearch-8.17.4/plugins |
重启elasticsearch
elasticsearch 数组和普通对象的区别
数组
- 数组是 同一字段的多个值的集合,例如:
tags: ["search", "database", "elasticsearch"]。 - 无需显式声明:Elasticsearch 不要求字段显式定义为数组类型,任何字段都可以包含多个值,自动被视为数组。
- 数组中的每个元素会被 独立索引(扁平化存储(Flattened)),但元素间的顺序和关联性会丢失。
- 匹配任意元素:查询数组字段时,只要文档的数组中包含任意一个匹配值,就会被命中。实际存储的倒排索引类似于:
1
2
3
4{
"user_id": 1,
"tags": ["search", "database", "elasticsearch"]
}1
2
3"search" → doc1
"database" → doc1
"elasticsearch" → doc1
普通对象
- 对象是 键值对的集合,用于表示结构化数据
- 隐式映射:Elasticsearch 会自动将内层对象映射为
object类型。 - 对象的字段会被 扁平化(Flattened)存储,但保留层级关系。
- 必须通过 完整路径 访问对象内的字段。
- 如果对象字段的值是多个对象(即对象数组),Elasticsearch 会将其 隐式合并,导致数据丢失
1
2
3
4
5
6
7
8
9
10{
"user": [
{ "name": "Alice", "age": 30 },
{ "name": "Bob", "age": 25 }
]
}
### 实际存储为:
### "user.name": ["Alice", "Bob"]
### "user.age": [30, 25]
### 问题:无法区分 `Alice` 对应 `age:30`,`Bob` 对应 `age:25`。
| 特性 | 数组(Array) | 普通对象(Object) |
|---|---|---|
| 数据结构 | 同一字段的多值集合(扁平化存储) | 键值对的集合(层级化存储) |
| 元素关系 | 元素独立,无关联性 | 字段间有关联性(如 user.name 和 user.age) |
| 多值对象处理 | 不适合(需用 nested 类型) |
隐式合并字段值,导致数据关联性丢失 |
| 查询方式 | 直接匹配任意元素 | 需指定字段路径(如 user.name) |
| 适用场景 | 标签、分类等多值字段 | 结构化数据(如用户信息、地址) |
关联关系数据实践
Object: (一对一) 优先考虑反范式化( Denormalization)
- 将关联数据冗余存储到主文档中,避免查询时进行跨文档关联。
- 读多写少、数据更新频率低的场景(如商品信息中嵌入分类名称)。
- 查询速度快,无需额外操作。数据冗余,更新时需要同步修改所有相关文档。
1
2
3
4
5
6
7
8{
"product_id": 1,
"name": "Laptop",
"category": {
"id": 10,
"name": "Electronics" // 直接冗余分类名称
}
}
嵌套对象(Nested Objects): (一对多,数组)当数据包含多个数值对象,同时有查询需求
- 将一对多关系的数据作为子对象嵌入主文档,使用
nested类型存储。 - 一对多关系且子对象需要独立查询(如订单中的多个商品项)。
- 子对象可独立查询,避免数据扁平化冲突。更新嵌套数据需重建整个文档,性能较低。
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### 定义 `nested` 类型的字段:
{
"mappings": {
"properties": {
"order_items": {
"type": "nested" // 声明为嵌套类型
}
}
}
}
### 插入数据
{
"order_id": 100,
"order_items": [
{ "product": "Keyboard", "price": 50 },
{ "product": "Mouse", "price": 20 }
]
}
### 使用 `nested` 查询
{
"query": {
"nested": {
"path": "order_items",
"query": {
"term": { "order_items.product": "Keyboard" }
}
}
}
}
父子文档(Parent-Child Relationships):(一对多,数组)关联文档更新非常频繁
- 通过
join字段建立父子文档关联,子文档与父文档存储在同一个分片 - 一对多关系且子文档频繁更新(如博客文章与评论)。
- 父子文档可独立更新。查询性能较低,需谨慎设计分片。
1 | ### 定义 `join` 字段: |
应用层关联(Application-Side Joins)(多对多)在应用代码中通过多次查询 Elasticsearch(或结合其他数据源)实现多对多关系的数据关联。
- 数据分散在不同索引或系统中。
- 需要灵活控制查询逻辑(如分页、过滤、排序)。需多次查询,增加网络延迟和代码复杂度。
- 多对多关系的数据量较大,不适合直接存储冗余。数据一致性需自行维护(如用户退群需更新两处)。
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## 用户索引 users
{
"user_id": 101,
"name": "Alice",
"group_ids": [1, 2] // 用户加入的群组 ID 列表
}
## 群组索引 groups
{
"group_id": 1,
"name": "Elasticsearch Fans",
"members": [101, 102] // 群组成员 ID 列表
}
## 下查users索引 id=101的用户加入的群组,后根据结果再次查询groups信息
## **查询用户加入的群组 ID 列表**:
GET /users/_search
{
"query": { "term": { "user_id": 101 } },
"_source": ["group_ids"] // 仅返回 group_ids 字段
}
## 响应结果: {"group_ids": [1, 2]}
## **根据群组 ID 列表查询群组详细信息**:
GET /groups/_search
{
"query": {
"terms": {
"group_id": [1, 2] // 使用上一步的 group_ids
}
}
}
Terms 查询(Terms Lookup)(多对多)通过 Elasticsearch 的 Terms Lookup 功能,直接从另一个文档中动态获取字段值,作为当前查询的条件。
- 多对多关系的双方数据均在 Elasticsearch 中。Terms Lookup 需要从另一个索引实时读取数据,可能影响查询速度。
- Elasticsearch 默认缓存 Terms Lookup 的结果,但频繁更新的字段会导致缓存频繁失效。
1
2
3
4
5
6
7
8
9
10
11
12
13GET /groups/_search
{
"query": {
"terms": {
"group_id": {
"index": "users", // 从 users 索引获取数据
"id": "101", // 用户 ID
"path": "group_ids" // 提取用户文档的 group_ids 字段
}
}
}
}
## 此查询等价于:SELECT * FROM groups WHERE group_id IN (SELECT group_ids FROM users WHERE user_id = 101);
| 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 反规范化 | 读多写少,数据更新不频繁 | 查询速度快 | 数据冗余,更新成本高 |
| 嵌套对象 | 一对多,子对象需独立查询 | 避免数据扁平化 | 更新需重建文档 |
| 父子文档 | 子文档频繁更新 | 父子独立更新 | 查询性能较低 |
| 应用层关联 | 数据分散在不同系统 | 灵活性高 | 网络开销大,延迟高 |
| Terms 查询 | 动态关联少量数据 | 无需预存关联数据 | 性能依赖外部索引 |
文档字段问题
- 避免过多字段
- 默认最大字段数1000,可设置index.mapping.total_fields.limit限定最大字段数
- 生产环境Dynamic问题
- true: 未知字段会u被自动加入索引
- false: 新字段不会被索引,但会保持在_source
- strict: 新字段不会被索引,文档写入失败(报错)
乐观锁
倒排索引
Elasticsearch 的倒排索引通过将文档内容转换为词项(Term)并建立词项到文档的映射,实现快速搜索。
倒排索引实现步骤
- 文档分析与分词
- 对文本进行分词、小写化、去除停用词(如 “is”, “a”)等处理。
- 生成词项字典
- 存储所有唯一词项,使用高效数据结构(如 FST)加速查找。
- 构建倒排列表
- 记录每个词项对应的文档 ID、词频(TF)、位置(Position)等信息。
- 存储优化
- 使用压缩技术(如增量编码、位压缩)减少存储空间。
具体示例
假设有两个文档:
- 文档 1(ID=1):
"Elasticsearch is a distributed search engine." - 文档 2(ID=2):
"Distributed systems are complex but interesting."
步骤 1:分析处理
- 分词并小写化,去除停用词后:
- 文档 1:
["elasticsearch", "distributed", "search", "engine"] - 文档 2:
["distributed", "systems", "complex", "interesting"]
- 文档 1:
步骤 2:构建倒排索引
| Term | 文档 ID | 词频(TF) | 位置(Positions) |
|---|---|---|---|
| elasticsearch | 1 | 1 | [0] |
| distributed | 1 | 1 | [1] |
| distributed | 2 | 1 | [0] |
| search | 1 | 1 | [2] |
| engine | 1 | 1 | [3] |
| systems | 2 | 1 | [1] |
| complex | 2 | 1 | [2] |
| interesting | 2 | 1 | [3] |
| 步骤 3:存储结构优化 |
- 词项字典:按字母排序(如
complex,distributed,elasticsearch…),便于二分查找。 - 倒排列表:合并相同词项的文档,例如
distributed的倒排列表为:1
2
3Term: distributed
-> Doc 1: TF=1, Positions: [1]
-> Doc 2: TF=1, Positions: [0]
搜索过程示例
当搜索关键词 "distributed" 时:
- 在词项字典中找到
distributed。 - 获取其倒排列表,得到文档 ID 1 和 2。
- 根据词频、位置等计算相关度(如 BM25 算法),返回结果。
相关性评分(boost)
- Index Boost
- boosting
- negative_boost
- function_socre
- rescore_query
- dis max query
- best_fields