Elasticsearch搜索引擎(数据建模)
一个优秀的elasticsearch工程师对elastic官网内容和案例模板要非常清楚,因为elasticsearch的api本就复杂规律性不像sql那么简单易用。
数据类型
和java类似
JSON 数据类型 | Elasticsearch 数据类型 | ES 类型说明 | 映射示例 | 注意事项 |
---|---|---|---|---|
string |
text |
全文检索字段 | "name": { "type": "text" } |
默认分词,适合模糊搜索 |
string |
keyword |
精确值字段 | "status": { "type": "keyword" } |
不分词,适合聚合/过滤 |
number (整数) |
integer /long |
整型数值 | "age": { "type": "integer" } |
根据数值范围选择类型 |
number (小数) |
float /double |
浮点数值 | "price": { "type": "float" } |
double 精度更高 |
boolean |
boolean |
布尔值 | "is_active": { "type": "boolean" } |
仅接受 true /false |
null |
忽略/保留 | 空值处理 | 无需显式声明 | 可通过 "null_value": "NULL" 替换空值 |
array |
同元素类型 | 多值字段 | "tags": [ "apple", "banana" ] |
数组元素必须为同一类型 |
object |
object |
JSON 对象 | "user": { "name": "Alice", "age": 30 } |
自动映射为嵌套结构 |
nested object |
nested |
独立索引的对象数组 | "orders": { "type": "nested" } |
需显式声明,保持数组对象独立性 |
date (字符串) |
date |
日期类型 | "created_at": { "type": "date", "format": "yyyy-MM-dd" } |
需指定格式,如 epoch_millis /strict_date_optional_time |
geo_point |
geo_point |
经纬度坐标 | "location": { "type": "geo_point" } |
支持 "lat,lon" 或 { "lat": 40.73, "lon": -74.1 } 格式 |
ip |
ip |
IP地址 | "client_ip": { "type": "ip" } |
支持IPv4/IPv6 |
更多参考官方文档
indexMapping
- 类似数据库中的表结构定义,主要作用如下:
- 定义 Index 下的字段名(Field Name)
- 定义字段的类型,比如数值型、字符串型、布尔型等
- 定义倒排索引相关的配置,比如是否索引、记录 position 等
GET /test_index/_mapping
查看
1 |
|
PUT my_index
修改/新增结构
1 |
|
注意事项
- Mapping 中的字段类型一旦设定后,禁止直接修改,原因如下:
- Lucene 实现的倒排索引生成后不允许修改
- 解决方案为:重新建立新的索引,然后做 reindex 重新导入的操作
elastic提供自动根据入参json自动创建对应的文档索引(用户也可以关闭)
dynamic
- 通过 dynamic 参数来控制字段的新增
- true(默认) 允许自动新增字段
- false 不允许自动新增字段,但是文档可以正常写入,但无法 对字段进行查询等操作
- strict 文档不能写入,报错
index
- 控制当前字段是否索引,默认为 true,即记录索引,false 不 记录,即不可搜索
分词器
分词器是 es 中专门处理分词的组件,英文为 Analyzer,它的组成
- Character Filters: 针对原始文本进行处理,比如去除 html 特殊标记符
- Tokenizer: 将原始文本按照一定规则切分为单词
- Token Filters: 针对 tokenizer 处理的单词就行再加工,比如转小写、删除或新增等处理
graph LR
A[Character Filters]-->B[Tokenizer]
B-->C[Token Filters]
通过analyzer可以对分词器进行测试
1 |
|
预定义分词器
- Standard :特性为: 按词切分,支持多语言 ,小写处理
- Simple:按照非字母切分 ,小写处理
- Whitespace:按照空格切分
- Stop:Stop Word 指语气助词等修饰性的词语,比如 the、an、的、这等等
- Keyword :不分词,直接将输入作为一个单词输出
- Pattern:通过正则表达式自定义分割符 ,默认是 \W+,即非字词的符号作为分隔符
自定义分词器
通过自定义分词流程中的Character Filters、Tokenizer 和 Token Filter 实现
Character Filters
- Character Filters :在 Tokenizer 之前对原始文本进行处理,比如增加、删除或替换字符等 • 自带的如下:
- HTML Strip 去除 html 标签和转换 html 实体
- Mapping 进行字符替换操作
- Pattern Replace 进行正则匹配替换
- 会影响后续 tokenizer 解析的 position 和 offset 信息
示例
1 |
|
Tokenizer
将原始文本按照一定规则切分为单词(term or token) 自带的如下:
- standard 按照单词进行分割
- letter 按照非字符类进行分割
- whitespace 按照空格进行分割
- UAX URL Email 按照 standard 分割,但不会分割邮箱和 url
- NGram 和 Edge NGram 连词分割
- Path Hierarchy 按照文件路径进行切割
示例
1 |
|
Token Filters
对于 tokenizer 输出的 单词(term) 进行增加、删除、修改等操作
自带如下
- lowercase 将所有 term 转换为小写
- stop 删除 stop words
- NGram 和 Edge NGram 连词分割
- Synonym 添加近义词的 term
示例
1 |
|
配置分词器
1 |
|
分词的时机
分词会在如下两个时机使用:
- 创建或更新文档时(Index Time),会对相应的文档进行分词处理
- 查询时(Search Time),会对查询语句进行分词
学会查看官方文档:[https://www.elastic.co/guide/en/elasticsearch/reference/8.1/a nalysis-analyzers.html](https://www.elastic.co/guide/en/elasticsearch/reference/8.1/a nalysis-analyzers.html)
多字段
允许对同一个字段采用不同的类型配置,通过fields实现
- 设定不同的分词器,比如对人名实现拼音搜索,只需要在人 名中新增一个子字段为 pinyin 即可
- 设定不同的类型,比如设为 text 和 keyword,同时实现全 文检索、排序、聚合的需求
官方文档:[https://www.elastic.co/guide/en/elasticsearch/reference/8.1/m ulti-fields.html](https://www.elastic.co/guide/en/elasticsearch/reference/8.1/m ulti-fields.html)
示例
1 |
|
Runtime field 类型
https://www.elastic.co/guide/en/elasticsearch/reference/current/runtime-indexed.html
在查询时动态生成的字段,可正常用于查询、排序、聚合分析等;
不占用存储空间,常见的应用场景如下
- 获取被 disabled 的 _source 中的字段
- 使用 grok 等从非结构化数据中动态提取相关字段
- 动态新增字段,无需重写数据(reindex)
- 覆盖当前的字段和字段类型
runtime field也需要被定义
使用时机
- 查询时指定,灵活性高,但增加了查询语句的复杂度
- Index Mapping 中提前指定,适用于需求明确后,固化字段,供 所有使用方共用
示例
1 |
|
注意事项
- 查询时为每个文档动态计算,耗费额外的资源
- 设置不合理的计算代码会拖慢整个集群性能,甚至导致节点崩溃
- 可以实现一些轻量级的运算,避免复杂计算逻辑