本文基于Elasticsearch7.x
关系数据库的三大范式
什么是范式? 范式就是数据建模的规则.
- 第一范式: 确保每列保持原子性.
数据库表中的所有字段都是不可分割的原子值. - 第二范式: 确保表中的每列都和主键相关.
一张数据库表中只能保存一种数据, 不可以把多种数据保存在同一张数据库表中. 比如订单相关的信息会设计三张表: 订单表, 订单项表, 商品表. - 第三范式: 确保每列都和主键直接相关, 而不是间接相关.
比如一个订单表里只需要保存userId, 不需要保存整个用户信息.
关系数据库的三大范式简化了写操作, 但读操作性能不高(join操作非常耗费性能), 并且扩展性很差. 而反范式化设计在文档中保存冗余的数据, 无需处理join操作, 数据读取性能很好, 但反范式化设计不适合数据频繁修改的场景.
Elasticsearch 处理存在关联关系的数据
Elasticsearch使用的是非关系型的数据存储引擎, 即反范式化设计, 那Elasticsearch如何处理存在关联关系的数据呢? 有三种方法, 即三种数据类型.
- 对象类型(Object)
- 嵌套类型(Nested)
- Join类型(Join)
对象类型(Object)
使用Object数据类型来将电影和演员信息存储到一个doc里.
(1) 定义Mapping
PUT /my_movies
{
"mappings": {
"properties": {
"title": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"actors": {
"properties": {
"first_name": {
"type": "keyword"
},
"last_name": {
"type": "keyword"
}
}
}
}
}
}
(2) 添加数据
PUT /my_movies/_doc/1
{
"title": "Speed",
"actors": [
{
"first_name": "Keanu",
"last_name": "Reeves"
},
{
"first_name": "Dennis",
"last_name": "Hopper"
}
]
}
(3) 搜索
GET /my_movies/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"actors.first_name": "Keanu"
}
},
{
"match": {
"actors.last_name": "Hopper"
}
}
]
}
}
}
结果:
"hits" : [
{
"_index" : "my_movies",
"_type" : "_doc",
"_id" : "1",
"_scor