在 ElasticSearch 中处理关联关系
- 在关系型数据库中,一般会考虑范式化数据;而在 ElasticSearch 中,往往考虑反范式化数据;
- 反范式化的好处:
- ElasticSearch 并不擅长处理关联关系,一般采用以下四种方法处理关联关系:
案例 | 搜索包含对象数组的文档
数据准备
DELETE my_movies
PUT my_movies
{
"mappings" : {
"properties" : {
"actors" : {
"properties" : {
"first_name" : {
"type" : "keyword"
},
"last_name" : {
"type" : "keyword"
}
}
},
"title" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
}
}
POST my_movies/_doc/1
{
"title":"Speed",
"actors":[
{
"first_name":"Keanu",
"last_name":"Reeves"
},
{
"first_name":"Dennis",
"last_name":"Hopper"
}
]
}
搜索数据
- 用第一个演员的名 + 第二个演员的姓居然搜出了结果;
- 原因:JSON 格式被处理成扁平式键值对的形式:
"actors.first_name":["Keanu","Dennis"]
"actors.last_name":["Reeves","Hopper"]
;
- 可以用 Nested Data Type 解决这个问题;
POST my_movies/_search
{
"query": {
"bool": {
"must": [
{"match": {"actors.first_name": "Keanu"}},
{"match": {"actors.last_name": "Hopper"}}
]
}
}
}
Nested Data Type
- 允许对象数组中的对象被独立索引;
- 使用 nested 和 properties 关键字,将所有 actors 索引到多个分隔的文档;
- 在内部,Nested 文档会被保存在两个 Lucene 文档中,在查询时做 Join 处理;
Nested Data Type | 搜索包含对象数组的文档
数据准备
DELETE my_movies
PUT my_movies
{
"mappings" : {
"properties" : {
"actors" : {
"type": "nested",
"properties" : {
"first_name" : {"type" : "keyword"},
"last_name" : {"type" : "keyword"}
}},
"title" : {
"type" : "text",
"fields" : {"keyword":{"type":"keyword","ignore_above":256}}
}
}
}
}
POST my_movies/_doc/1
{
"title":"Speed",
"actors":[
{
"first_name":"Keanu",
"last_name":"Reeves"
},
{
"first_name":"Dennis",
"last_name":"Hopper"
}
]
}
Nested 查询
- 在 Nested 查询中,错误的结果就不会命中了;
POST my_movies/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"title": "Speed"
}
},
{
"nested": {
"path": "actors",
"query": {
"bool": {
"must": [
{
"match": {
"actors.first_name": "Keanu"
}
},
{
"match": {
"actors.last_name": "Hopper"
}
}
]
}
}
}
}
]
}
}
}
对 Nested 对象做聚合分析
POST my_movies/_search
{
"size": 0,
"aggs": {
"actors": {
"nested": {
"path": "actors"
},
"aggs": {
"actor_name": {
"terms": {
"field": "actors.first_name",
"size": 10
}
}
}
}
}
}
对 Nested 对象做普通聚合是无效的
POST my_movies/_search
{
"size": 0,
"aggs": {
"NAME": {
"terms": {
"field": "actors.first_name",
"size": 10
}
}
}
}
网友评论