映射配置
映射(Mapping)定义了文档的结构,包括字段类型、分析器等配置。
映射类型
核心数据类型
| 类型 | 说明 | 示例 |
|---|---|---|
text | 全文搜索,会分词 | 文章内容、标题 |
keyword | 精确匹配,不分词 | 标签、状态、ID |
integer | 32 位整数 | 年龄、数量 |
long | 64 位整数 | ID、时间戳 |
float | 单精度浮点数 | 价格 |
double | 双精度浮点数 | 精确计算 |
boolean | 布尔值 | 是否激活 |
date | 日期时间 | 创建时间 |
binary | 二进制数据 | 图片 Base64 |
range | 范围类型 | 年龄范围 |
复杂数据类型
# 对象类型
PUT /articles
{
"mappings": {
"properties": {
"author": {
"properties": {
"name": { "type": "text" },
"email": { "type": "keyword" }
}
}
}
}
}
# 嵌套类型(数组中的对象独立索引)
PUT /articles
{
"mappings": {
"properties": {
"comments": {
"type": "nested",
"properties": {
"user": { "type": "keyword" },
"content": { "type": "text" }
}
}
}
}
}
text vs keyword
PUT /articles
{
"mappings": {
"properties": {
"title": {
"type": "text", # 全文搜索
"analyzer": "ik_max_word"
},
"status": {
"type": "keyword" # 精确匹配
},
"category": {
"type": "text", # 同时支持两种
"fields": {
"keyword": {
"type": "keyword"
}
}
}
}
}
}
# 查询时:
# 全文搜索:match { "category": "技术" }
# 精确匹配:term { "category.keyword": "技术" }
创建映射
创建索引时指定映射
PUT /articles
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
},
"content": {
"type": "text",
"analyzer": "ik_max_word"
},
"author": {
"type": "keyword"
},
"category": {
"type": "keyword"
},
"views": {
"type": "integer"
},
"price": {
"type": "float"
},
"is_published": {
"type": "boolean"
},
"tags": {
"type": "keyword"
},
"created_at": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
},
"location": {
"type": "geo_point"
}
}
}
}
动态映射
Elasticsearch 会自动推断字段类型:
# 插入文档时自动创建映射
POST /articles/_doc
{
"title": "测试文章", # 自动映射为 text
"views": 100, # 自动映射为 long
"is_active": true, # 自动映射为 boolean
"created_at": "2024-01-15" # 自动映射为 date
}
动态映射规则:
| JSON 类型 | Elasticsearch 类型 |
|---|---|
| null | 不添加字段 |
| boolean | boolean |
| integer | long |
| float | float |
| string | text + keyword |
| array | 取数组第一个元素的类型 |
关闭动态映射
PUT /articles
{
"mappings": {
"dynamic": false, # 忽略未知字段
"properties": {
"title": { "type": "text" }
}
}
}
# 或严格模式(遇到未知字段报错)
PUT /articles
{
"mappings": {
"dynamic": "strict",
"properties": {
"title": { "type": "text" }
}
}
}
更新映射
添加新字段
PUT /articles/_mapping
{
"properties": {
"summary": {
"type": "text"
},
"rating": {
"type": "float"
}
}
}
注意:已存在字段的类型不能修改,如需修改需要重建索引。
分析器
内置分析器
| 分析器 | 说明 |
|---|---|
standard | 默认分析器,按空格分词 |
simple | 按非字母分词 |
whitespace | 按空格分词 |
stop | standard + 停用词过滤 |
keyword | 不分词,整体作为一个词 |
pattern | 使用正则表达式分词 |
language | 特定语言分析器 |
测试分析器
GET /_analyze
{
"analyzer": "standard",
"text": "Hello World, Elasticsearch!"
}
# 使用索引的分析器
GET /articles/_analyze
{
"field": "title",
"text": "测试分词效果"
}
自定义分析器
PUT /articles
{
"settings": {
"analysis": {
"analyzer": {
"my_analyzer": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase",
"my_stopwords"
]
}
},
"filter": {
"my_stopwords": {
"type": "stop",
"stopwords": ["的", "是", "在"]
}
}
}
},
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "my_analyzer"
}
}
}
}
字段属性
常用属性
PUT /articles
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart",
"boost": 2.0, # 权重
"index": true, # 是否索引(默认 true)
"store": false, # 是否单独存储
"norms": true, # 是否存储评分因子
"term_vector": "no" # 词向量存储
},
"content": {
"type": "text",
"index": false # 不索引,不能搜索
},
"views": {
"type": "integer",
"doc_values": true, # 用于排序和聚合
"index": false # 只用于排序聚合,不用于搜索
},
"internal_notes": {
"type": "text",
"index": false, # 不索引
"store": true # 单独存储
}
}
}
}
copy_to
将多个字段值复制到一个字段:
PUT /articles
{
"mappings": {
"properties": {
"title": {
"type": "text",
"copy_to": "full_content"
},
"content": {
"type": "text",
"copy_to": "full_content"
},
"full_content": {
"type": "text"
}
}
}
}
# 搜索时只需查询 full_content 字段
GET /articles/_search
{
"query": {
"match": {
"full_content": "搜索关键词"
}
}
}
小结
本章我们学习了:
- 核心数据类型和复杂数据类型
- text 和 keyword 的区别
- 动态映射
- 分析器配置
- 字段属性详解
练习
- 创建一个商品索引,定义合适的字段类型
- 配置一个自定义分析器
- 使用 copy_to 实现多字段搜索
- 测试不同分析器的分词效果