Elasticsearch处理表关联关系的N种方式

news2024/11/17 9:35:11

Elasticsearch处理表关联关系是比较复杂的问题,处理不好会出现性能问题、数据一致性问题等;

今天我们特意分享一下几种方式,对象类型(宽表)、嵌套类型、父子关联关系、应用端关联,每种方式都有特定的业务需求,具体可以根据业务场景选择,废话少数,现在开始。

一、对象类型

我们以博客为例,在每一博客的文档中都保留作者的信息,如果作者信息发生变化,需要修改相关的博客文档。

1、创建博客的索引

PUT /nandao_blog_index
{
	"mappings": {
		"properties": {
			"content": {
				"type": "text"
			},
			"time": {
				"type": "date"
			},
			"user": {
				"properties": {
					"city": {
						"type": "text"
					},
					"userid": {
						"type": "long"
					},
					"username": {
						"type": "keyword"
					}
				}
			}
		}
	}
}

结果:

{
  "acknowledged" : true,
  "shards_acknowledged" : true,
  "index" : "nandao_blog_index"
}

 2、修改映射,添加博客的name

POST /nandao_blog_index/_mapping
{
	"properties": {
		"name": {
			"type": "text"
		}
	}
}

结果:


{
  "acknowledged" : true
}

 3、插入两条条 blog信息

  PUT /nandao_blog_index/_doc/1
 {
	"content": "I like Elasticsearch",
	"time": "2022‐01‐01T00:00:00",
	"user": {
		"userid": 1,
		"username": "Nandao",
		"city": "Changsha"
	}
}

  PUT /nandao_blog_index/_doc/2
 {
	"content": "I like Java",
	"time": "2022‐01‐01T00:00:00",
	"user": {
		"userid": 1,
		"username": "Nandao",
		"city": "Changsha"
	}
}

4、查询 blog信息

 POST /nandao_blog_index/_search
 {
	"query": {
		"bool": {
			"must": [{
					"match": {
						"content": "Elasticsearch"
					}
				},
				{
					"match": {
						"user.username": "Nandao"
					}
				}
			]
		}
	}
}

结果就会查到一条信息 

 5、包含对象数组的文档,创建索引

PUT /nandao_movies_index
{
	"mappings": {
		"properties": {
			"actors": {
				"properties": {
					"first_name": {
						"type": "keyword"
					},
					"last_name": {
						"type": "keyword"
					}
				}
			},
			"title": {
				"type": "text",
				"fields": {
					"keyword": {
						"type": "keyword",
						"ignore_above": 256
					}
				}
			}
		}
	}
}
 

6、创建一条数据:

 POST /nandao_movies_index/_doc/1 
 {
	"title": "Speed",
	"actors": [
	    {
			"first_name": "Keanu",
			"last_name": "Reeves"
		},
		{
			"first_name": "Dennis",
			"last_name": "Hopper"
		}
	]
}

7、查询电影信息

 POST /nandao_movies_index/_search 
 {
	"query": {
		"bool": {
			"must": [{
					"match": {
						"actors.first_name": "Keanu"
					}
				},
				{
					"match": {
						"actors.last_name": "Hopper"
					}
				}
			]
		}
	}
}

结果:

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.723315,
    "hits" : [
      {
        "_index" : "erpx_test_order_array",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.723315,
        "_source" : {
          "title" : "Speed",
          "actors" : [
            {
              "first_name" : "Keanu",
              "last_name" : "Reeves"
            },
            {
              "first_name" : "Dennis",
              "last_name" : "Hopper"
            }
          ]
        }
      }
    ]
  }
}

 搜到了不需要的结果,存储时,内部对象的边界并没有考虑在内,JSON格式被处理成扁平式键值对的结构。当对多个字段进行查询时,导致了意外的搜索结果。可以用Nested Data Type解决这个问题 ,下面我们会分析。

二、嵌套类型

1、场景索引

PUT /nandao_movies_index_nested 
{
	"mappings": {
		"properties": {
			"actors": {
				"type": "nested",
				"properties": {
					"first_name": {
						"type": "keyword"
					},
					"last_name": {
						"type": "keyword"
					}
				}
			},
			"title": {
				"type": "text",
				"fields": {
					"keyword": {
						"type": "keyword",
						"ignore_above": 256
					}
				}
			}
		}
	}
}

2、添加数据

POST /nandao_movies_index_nested/_doc/1 
{
	"title": "Speed",
	"actors": [{
			"first_name": "Keanu",
			"last_name": "Reeves"
		},

		{
			"first_name": "Dennis",
			"last_name": "Hopper"
		}

	]
}

3、Nested方式 查询

POST /nandao_movies_index_nested/_search 
 {
	"query": {
		"bool": {
			"must": [{
					"match": {
						"title": "Speed"
					}
				},
				{
					"nested": {
						"path": "actors",
						"query": {
							"bool": {
								"must": [{
										"match": {
											"actors.first_name": "Keanu"
										}
									},

									{
										"match": {
											"actors.last_name": "Hopper"
										}
									}
								]
							}
						}
					}
				}
			]
		}
	}
}

显然结果 没有查到数据:

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 0,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  }
}

 

4、Nested Aggregation 查询

 POST /nandao_movies_index_nested/_search 
 {
	"size": 0,
	"aggs": {
		"actors": {
			"nested": {
				"path": "actors"
			},
			"aggs": {
				"actor_name": {
					"terms": {
						"field": "actors.first_name",
						"size": 10
					}
				}
			}
		}
	}
}

5、普通 aggregation不工作查询

 POST /erpx_test_order_nested/_search 
 {
	"size": 0,
	"aggs": {
		"NAME": {
			"terms": {
				"field": "actors.first_name",
				"size": 10
			}
		}
	}
}

三、父子关系类型:即join 联合查询

对象和Nested对象的局限性: 每次更新,可能需要重新索引整个对象(包括根对象和嵌套对象)
ES提供了类似关系型数据库中Join 的实现。

使用Join数据类型实现,可以通过维护Parent/ Child的关系,从而分离两个对象父文档和子文档是两个独立的文档更新父文档无需重新索引子文档。

子文档被添加,更新或者删除也不会影响到父文档和其他的子文档。

1、创建父子索引

PUT /nandao_relation_index 
{
	"settings": {
		"number_of_shards": 2
	},
	"mappings": {
		"properties": {
			"blog_comments_relation": {
				"type": "join",
				"relations": {
					"blog": "comment"
				}
			},
			"content": {
				"type": "text"
			},
			"title": {
				"type": "keyword"
			}
		}
	}
}

解释:

 

 

2、创建两个父文档

PUT /nandao_relation_index/_doc/blog1
 {
	"title": "Learning Elasticsearch",
	"content": "learning ELK ",
	"blog_comments_relation": {
		"name": "blog"
	}
}

PUT /nandao_relation_index/_doc/blog2 
{
	"title": "Learning Hadoop",
	"content": "learning Hadoop",
	"blog_comments_relation": {
		"name": "blog"
	}
}

解释:

 

 3、创建三个子文档

PUT /nandao_relation_index/_doc/comment1?routing=blog1 
{
	"comment": "I am learning ELK",
	"username": "Jack",
	"blog_comments_relation": {
		"name": "comment",
		"parent": "blog1"
	}
}

PUT /nandao_relation_index/_doc/comment2?routing=blog2
  {
  "comment":"I like Hadoop!!!!!",
  "username":"Jack",
  "blog_comments_relation":{
  "name":"comment",
  "parent":"blog2"
  }
  }

 PUT /nandao_relation_index/_doc/comment3?routing=blog2 
 {
	"comment": "Hello Hadoop",
	"username": "Bob",
	"blog_comments_relation": {
		"name": "comment",
		"parent": "blog2"
	}
}

4、查询所有文档

POST /nandao_relation_index/_search

显示父子五个文档:

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 2,
    "successful" : 2,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 5,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "erpx_test_order_test",
        "_type" : "_doc",
        "_id" : "blog1",
        "_score" : 1.0,
        "_source" : {
          "title" : "Learning Elasticsearch",
          "content" : "learning ELK ",
          "blog_comments_relation" : {
            "name" : "blog"
          }
        }
      },
      {
        "_index" : "erpx_test_order_test",
        "_type" : "_doc",
        "_id" : "blog2",
        "_score" : 1.0,
        "_source" : {
          "title" : "Learning Hadoop",
          "content" : "learning Hadoop",
          "blog_comments_relation" : {
            "name" : "blog"
          }
        }
      },
      {
        "_index" : "erpx_test_order_test",
        "_type" : "_doc",
        "_id" : "comment1",
        "_score" : 1.0,
        "_routing" : "blog1",
        "_source" : {
          "comment" : "I am learning ELK",
          "username" : "Jack",
          "blog_comments_relation" : {
            "name" : "comment",
            "parent" : "blog1"
          }
        }
      },
      {
        "_index" : "erpx_test_order_test",
        "_type" : "_doc",
        "_id" : "comment2",
        "_score" : 1.0,
        "_routing" : "blog2",
        "_source" : {
          "comment" : "I like Hadoop!!!!!",
          "username" : "Jack",
          "blog_comments_relation" : {
            "name" : "comment",
            "parent" : "blog2"
          }
        }
      },
      {
        "_index" : "erpx_test_order_test",
        "_type" : "_doc",
        "_id" : "comment3",
        "_score" : 1.0,
        "_routing" : "blog2",
        "_source" : {
          "comment" : "Hello Hadoop",
          "username" : "Bob",
          "blog_comments_relation" : {
            "name" : "comment",
            "parent" : "blog2"
          }
        }
      }
    ]
  }
}

 5、根据父文档ID查看

GET /nandao_relation_index/_doc/blog2

结果:


{
  "_index" : "nandao_relation_index",
  "_type" : "_doc",
  "_id" : "blog2",
  "_version" : 1,
  "_seq_no" : 1,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "title" : "Learning Hadoop",
    "content" : "learning Hadoop",
    "blog_comments_relation" : {
      "name" : "blog"
    }
  }
}

 6、根据Parent Id 查询

POST /nandao_relation_index/_search 
{
	"query": {
		"parent_id": {
			"type": "comment",
			"id": "blog2"
		}
	}
}

结果:


{
  "took" : 6,
  "timed_out" : false,
  "_shards" : {
    "total" : 2,
    "successful" : 2,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 0.53899646,
    "hits" : [
      {
        "_index" : "erpx_test_order_test",
        "_type" : "_doc",
        "_id" : "comment2",
        "_score" : 0.53899646,
        "_routing" : "blog2",
        "_source" : {
          "comment" : "I like Hadoop!!!!!",
          "username" : "Jack",
          "blog_comments_relation" : {
            "name" : "comment",
            "parent" : "blog2"
          }
        }
      },
      {
        "_index" : "erpx_test_order_test",
        "_type" : "_doc",
        "_id" : "comment3",
        "_score" : 0.53899646,
        "_routing" : "blog2",
        "_source" : {
          "comment" : "Hello Hadoop",
          "username" : "Bob",
          "blog_comments_relation" : {
            "name" : "comment",
            "parent" : "blog2"
          }
        }
      }
    ]
  }
}

 7、 Has Child 查询,返回父文档

POST /nandao_relation_index/_search 
{
	"query": {
		"has_child": {
			"type": "comment",
			"query": {
				"match": {
					"username": "Jack"
				}
			}
		}
	}
}

结果:


{
  "took" : 14,
  "timed_out" : false,
  "_shards" : {
    "total" : 2,
    "successful" : 2,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "erpx_test_order_test",
        "_type" : "_doc",
        "_id" : "blog1",
        "_score" : 1.0,
        "_source" : {
          "title" : "Learning Elasticsearch",
          "content" : "learning ELK ",
          "blog_comments_relation" : {
            "name" : "blog"
          }
        }
      },
      {
        "_index" : "erpx_test_order_test",
        "_type" : "_doc",
        "_id" : "blog2",
        "_score" : 1.0,
        "_source" : {
          "title" : "Learning Hadoop",
          "content" : "learning Hadoop",
          "blog_comments_relation" : {
            "name" : "blog"
          }
        }
      }
    ]
  }
}

 注意:
1)父文档和子文档必须存在相同的分片上,能够确保查询join 的性能。
2)当指定子文档时候,必须指定它的父文档ld。使用routing参数来保证,分配到
相同的分片。

 四、应用端关联

1、此方案比较好理解,就是多长查询,下一次查询依赖上一次查询结果。

常用的嵌套文档和父子文档对比:

 到此、es相关的DSL语句分享完毕,后期我们分享一下相关的javaAPI,也是实战的必经之路,敬请期待!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/130186.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CycloneDDS(3)安全Security

本规范定义了符合DDS实现的安全模型和服务插件接口(SPI)架构。DDS安全模型通过DDS实现调用这些SPI来实现。 构成DDS安全模型的三个插件是: 1、身份验证服务插件 提供验证调用DDS操作的应用程序和/或用户身份的方法。包括在参与者之间执行相互身份验证和建立共享秘密的设施…

深度学习模型训练的tricks总结

学习率角度 学习率是一个非常非常重要的超参数,这个参数呢,面对不同规模、不同batch-size、不同优化方式、不同数据集,其最合适的值都是不确定的,我们无法光凭经验来准确地确定lr的值,我们唯一可以做的,就…

从零开始配置vim(30)——DAP的其他配置

很抱歉这么久才来更新这一系列,主要是来新公司还在试用期,我希望在试用期干出点事来,所以摸鱼的时间就少了。加上前面自己阳了休息了一段时间。在想起来更新就过去一个多月了。废话不多说了,让我们开始进入正题。 在前一章&#…

JUC 并发进阶学习(一)

该学习笔记是本人依据相关的学习视频整体汇总,相关的视频学习可以自己去搜看看。 【狂神说Java】JUC并发编程最新版通俗易懂_哔哩哔哩_bilibili 一、什么是JUC 从中就可以看出JUC,实质就是三个包,后面晖详细说明三个包下各个类功能。 java.…

程序员的测试课

git项目地址:GitHub - dreamhead/geektime-todo: Geektime Todo is a demo todo project for Geektime column. 1、实现一个Todo应用 设计规范 1、对于输入参数的检测,由入口部分代码进行处理。如空字符串。 2、Repository 的问题以运行时异常 的形式抛…

Django+Celery+Flower实现异步和定时任务及其监控告警

用Django框架进行web开发非常的快捷方便,但Django框架请求/响应是同步的。但我们在实际项目中经常会碰到一些耗时的不能立即返回请求结果任务如:数据爬取、发邮件等,如果常时间等待对用户体验不是很好,在这种情况下就需要实现异步…

SOFA Weekly|2023 我们一起加油、本周 Contributor QA

SOFA WEEKLY | 每周精选 筛选每周精华问答,同步开源进展欢迎留言互动~SOFAStack(Scalable Open Financial Architecture Stack)是蚂蚁集团自主研发的金融级云原生架构,包含了构建金融级云原生架构所需的各个组件&#…

RocketMQ 搭建

目录 1、什么是MQ?为什么要用MQ? 2、MQ的优缺点 3、几大MQ产品特点比较 4.RocketMQ在Windows的启动 1.下载RocketMQ 4.7.1版本 2.解压到本地磁盘并配置好JAVA_HOME和ROCKETMQ_HOME 3.修改runserver.cmd 4.启动server 5.修改runbroker.cmd 6.启动…

ROS2 基础概念 服务

ROS2 基础概念 服务1. Services2. 服务类型3. 查找服务4. 服务请求1. Services 服务基于 请求-应答 模型,而不是话题的 发布-订阅 模型 虽然话题允许节点订阅数据流并获得持续更新,但服务 仅在客户端专门调用时提供数据 还是启动海龟及其遥控节点为例&…

[标准库]STM32F103R8T6 点灯以及按键扫描

刚开始学32的时候,选择了基于HAL库进行开发,原因是HAL比较容易上手,像点灯、输出PWM、按键输入这种操作都很快捷。但是到ADCDMA这部分的时候发现,HAL库有一些地方我认为不是很合理和方便。比如DMA中断这部分,ST官方给出…

音视频开发系列--H264编解码总结

一、概述 H264,通常也被称之为H264/AVC(或者H.264/MPEG-4 AVC或MPEG-4/H.264 AVC) 对摄像头采集的每一帧视频需要进行编码,由于视频中存在空间和时间的冗余,需要用算法来去除这些冗余。H264是专门去除这些冗余的算法…

王者荣耀崩溃解决记录

王者荣耀竟然崩溃了 上周玩王者荣耀,突然就进不去了,点击开始游戏后应用直接就崩溃退出了。 第一反应,肯定是反馈给游戏客服。但是果然腾讯的游戏是找不到真客服的,全部都是机器人处理的,给了我一个毫无用处的官方回…

springboot中配置文件优先级以及分类,这你都可以不会吗?不会赶紧进来学( ̄(∞) ̄)

各位小伙伴大家好呀┗( ▔, ▔ )┛,马上过年了,但是感觉没啥期待的哈哈哈哈哈,现在的年说实话真的挺没劲的呜呜。 言归正传,我们大家在使用springboot时难免会写各种各样的配置信息,比如port,jdbc啊这些&am…

2022这一年:阳了、变轨和逆风

又到年末了,2022这一年应该会让人记忆深刻,于我而言这一年的感受有明显的分界线,在此之前的世界温暖一些,提供着能量,让人心生探索它的纷繁多彩;今年世界变得寒冷了,展示着它的严酷与无情。阳了…

再学C语言20:循环控制语句——for循环

在while循环中,建立一个重复执行固定次数的循环涉及到3个动作: 1)初始化一个计数器 2)计数器与某个有限的值比较 3)每次执行循环,要在循环体中让计数器的值递增 其中,计数器的初始化在循环之…

【pandas】教程:6-如何计算摘要统计

Pandas 计算摘要统计 本节使用的数据为 data/titanic.csv,链接为 pandas案例和教程所使用的数据-机器学习文档类资源-CSDN文库 加载数据 import pandas as pdtitanic pd.read_csv("data/titanic.csv") titanic.head()PassengerId Survived Pclass \…

#Z0424. 树上的旅行

题目 Description 给出一棵有N个结点的树,给出Q个询问,求结点xj过结点K到节点yj的最短距离 Format Input 第一行一个数n 接下来共有n-1行,三个数u,v,len表示u和v之间存在一条边长为len 再给你Q,K。代表有Q个询问&#xff0…

视频 | bedtools使用介绍1

点击阅读原文跳转完整教案。基因组中的趣事(二)- 最长的基因2.7 million,最短的基因只有8 nt却能编码基因组中的趣事(一):这个基因编码98种转录本1 Linux初探,打开新世界的大门1.1 Linux系统简介…

10000+条数据的内容滚动功能如何实现?

遇到脑子有问题的产品经理该怎么办?如果有这么一个需求要你在一个可视区范围内不间断循环滚动几千上万条数据你会怎么去实现? 且不说提这个需求的人是不是脑子有问题,这个需求能不能实现?肯定是可以的,把数据请求回来渲…

2022蓝桥杯省赛C++A组初尝试

前言 耗时三个半小时,看看自己不懂的有多少,以便明确后续备赛2023方向 耗时3个半小时,只拿了18分,没学过,时间再多也做不出来,有奥数那感觉了 据说蓝桥杯省3得做对 2填空 2大题(30分&#x…