关联关系处理
ES不擅长处理管理型数据库中的关联关系,比如文章表blog与评论表comment之间通过blog_id关联,在ES中可以通过如下两种手段变相解决:
Nested Object
Parent/Child
评论Comment:
文章Id blog_id
评论人 username
评论日期 date
评论内容 content
Nested Object
关系型数据库中的关联关系:
在es中其中的一个实现方式如下所示:
把comment具体的内容直接整合进blog文档中,这样在获取blog的内容的时候可以直接取到文档的评论
现在对comments进行如下查询:
返回lee评论的,并且他的评论内容有thanks关键词的所有blog,结果如下图所示:
很明显查询结果并不符合条件,原因如下:
comments如果不设定其类型的话默认是Object Array
,存储结构类似下面的形式:(一个object)
解决办法
Nested object
可以解决这个问题:
mapping设置为如下所示:
PUT blog_index_nested
{
"mappings": {
"doc":{
"properties": {
"title":{
"type":"text",
"fields": {
"keyword":{
"type": "keyword"
}
}
},
"publish_date":{
"type": "date"
},
"author":{
"type": "keyword"
},
"abstract":{
"type": "text"
},
"url":{
"enabled":"false"
},
"comments":{
"type": "nested",
"properties": {
"username":{
"type":"keyword",
"ignore_above":100
},
"data":{
"type":"date"
},
"content":{
"type":"text"
}
}
}
}
}
}
}
插入相同数据:
PUT blog_index_nested/doc/1
{
"title":"Blog Number One",
"auther":"alfred",
"comments":[
{
"username":"lee",
"date":"2017-01-02",
"content":"awesome article!"
},
{
"username":"fax",
"date":"2017-04-02",
"content":"thanks"
}
]
}
使用如下方法进行查询:
GET blog_index_nested/_search
{
"query": {
"nested": {
"path": "comments",
"query": {
"bool": {
"must": [
{
"match": {
"comments.username": "lee"
}
},
{
"match": {
"comments.content": "thanks"
}
}
]
}
}
}
}
}
返回结果为空(满足条件)
这是因为Nested Object Array
的存储结构类似下面的形式:(nested object独立存在)
{
"title":"Blog Number One",
"auther":"alfred"
}
{
"comments.username":"lee",
"comments.date":"2017-01-02",
"comments.content":"awesome article!"
}
{
"comments.username":"fax",
"comments.date":"2017-04-02",
"comments.content":"thanks"
}
Parent/Child
ES还提供了类似关系数据库中join的实现方式,使用join
数据类型
PUT blog_index_parent_child
{
"mappings": {
"doc":{
"properties": {
"join":{
"type": "join",
"relations":{
"blog":"comment"
}
}
}
}
}
}
创建父子文档
#创建父文档
PUT blog_index_parent_child/doc/1
{
"title":"blog",
"join":"blog"
}
#创建子文档
PUT blog_index_parent_child/doc/comment-1?routing=1
{
"comment":"comment world",
"join":{
"name":"comment",
"parent":1
}
}
常见query语法包括如下几种:
parent_id
: 返回某父文档的子文档has_child
: 返回包含某子文档的父文档has_parent
: 返回包含某父文档的子文档
(1)parent_id查询
:返回某父文档的子文档
GET blog_index_parent_child/_search
{
"query": {
"parent_id":{
"type":"comment",
"id":"1"
}
}
}
#parent_id关键词,type指明子文档类型,id指明父文档id
(2)has_child查询
: 返回包含某子文档的父文档
GET blog_index_parent_child/_search
{
"query": {
"has_child": {
"type": "comment",
"query": {
"match": {
"comment": "world"
}
}
}
}
}
(3)has_parent查询
: 返回包含某父文档的子文档
GET blog_index_parent_child/_search
{
"query": {
"has_parent": {
"parent_type": "blog",
"query": {
"match": {
"title": "blog"
}
}
}
}
}
nested_vs_parent_child
建议尽量选择nested object
来解决问题