文档章节

Elasticsearch数据建模-关联查询

莫问viva
 莫问viva
发布于 2016/06/06 14:56
字数 1668
阅读 123
收藏 9

在真实的世界中,关联关系很重要:博客文章有评论,银行账户有交易,客户有银行账户,订单有行项目,目录也拥有文件和子目录。

在关系数据库中,处理关联关系的方式让你不会感到意外:

  • 每个实体(或者行,在关系世界中)可以通过一个主键唯一标识。
  • 实体是规范化了的。对于一个唯一的实体,它的数据仅被存储一次,而与之关联的实体则仅仅保存它的主键。改变一个实体的数据只能发生在一个地方。
  • 在查询期间,实体可以被联接(Join),它让跨实体查询成为可能。
  • 对于单个实体的修改是原子性,一致性,隔离性和持久性的。(参考ACID事务获取更多相关信息。)
  • 绝大多数的关系型数据库都支持针对多个实体的ACID事务。

但是关系型数据库也有它们的局限,除了在全文搜索领域它们拙劣的表现外。在查询期间联接实体是昂贵的 - 联接的实体越多,那么查询的代价就越大。对不同硬件上的实体执行联接操作的代价太大以至于它甚至是不切实际的。这就为在单个服务器上能够存储的数据量设下了一个限制。

ES,像多数NoSQL数据库那样,将世界看作是平的。一个索引就是一系列独立文档的扁平集合。一个单一的文档应该包括用来判断它是否符合一个搜索请求的所有信息。

虽然在ES中改变一份文档的数据是符合ACIDic的,涉及到多份文档的事务就不然了。在ES中,当事务失败后是没有办法将索引回滚到它之前的状态的。

这个扁平化的世界有它的优势:

  • 索引是迅速且不需要上锁的。
  • 搜索是迅速且不需要上锁的。
  • 大规模的数据可以被分布到多个节点上,因为每份文档之间是独立的。

但是关联关系很重要。我们需要以某种方式将扁平化的世界和真实的世界连接起来。在ES中,有4中常用的技术来管理关联数据:

通常最终的解决方案会结合这些方案的几种。

应用端关联(Application-side joins)

我们可以通过在应用中实现联接来(部分)模拟一个关系型数据库。比如,当我们想要索引用户和他们的博客文章时。在关系型的世界中,我们可以这样做:

 

PUT /my_index/user/1  (1)
{
  "name":     "John Smith",
  "email":    "john@smith.com",
  "dob":      "1970/10/24"
}

PUT /my_index/blogpost/2 (2)
{
  "title":    "Relationships",
  "body":     "It's complicated...",
  "user":     1 (3)
}

 

 

(1)(2) 索引,类型以及每份文档的ID一起构成了主键。

(3) 博文通过保存了用户的ID来联接到用户。由于索引和类型是被硬编码到了应用中的,所以这里并不需要。

通过用户ID等于1来找到对应的博文很容易:

GET /my_index/blogpost/_search
{
  "query": {
    "filtered": {
      "filter": {
        "term": { "user": 1 }
      }
    }
  }
}

 

 

为了找到用户John的博文,我们可以执行两条查询:第一条查询用来得到所有名为John的用户的IDs,第二条查询通过这些IDs来得到对应文章:

 

 

GET /my_index/user/_search
{
  "query": {
    "match": {
      "name": "John"
    }
  }
}

GET /my_index/blogpost/_search
{
  "query": {
    "filtered": {
      "filter": {
        "terms": { "user": [1] }  (1)
      }
    }
  }
}

 

 

(1) 传入到terms过滤器的值是第一条查询的结果

 

 

应用端联接最大的优势在于数据是规范化了的。改变用户的名字只需要在一个地方操作:用户对应的文档。劣势在于你需要在搜索期间运行额外的查询来联接文档。

在这个例子中,只有一位用户匹配了第一条查询,但是在实际应用中可能轻易就得到了数以百万计的名为John的用户。将所有的IDs传入到第二个查询中会让该查询非常巨大,它需要执行百万计的term查询。

这种方法在第一个实体的文档数量较小并且它们很少改变时合适(这个例子中实体指的是用户)。这就使得通过缓存结果来避免频繁查询成为可能。

数据非规范化(Denormalizing Your Data)

 

让ES达到最好的搜索性能的方法是采用更直接的办法,通过在索引期间反规范化你的数据。通过在每份文档中包含冗余数据来避免联接。

如果我们需要通过用户的名字来搜索博文,仅需要将作者的名字包含在博文文档中即可。

 

PUT /my_index/user/1
{
  "name":     "John Smith",
  "email":    "john@smith.com",
  "dob":      "1970/10/24"
}

PUT /my_index/blogpost/2
{
  "title":    "Relationships",
  "body":     "It's complicated...",
  "user":     {
    "id":       1,
    "name":     "John Smith" (1)
  }
}

 

 

(1)中用户的部分数据已经非规范化的包含在了博文文档中了。

 

现在我们可以通过一个查询语句来

GET /my_index/blogpost/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "title":     "relationships" }},
        { "match": { "user.name": "John"          }}
      ]
    }
  }
}

 

 

查询作者名字中包含john,博文标题包含relationships的博文了。

 

非规范化数据的优势在于查询速度快,以为每个文档中都包含了可以查询的信息,不需要进行额外的联接查询。

嵌套对象(Nested Object)

考虑到在ES里面建立、删除和更新一个单一文本是原子性的,那么僵相关试题保存在同一个文本里面是有意义的。例如,我们可以保存一篇博文以及该博文的评论在一个文档中,博文评论以数组形式提供:

 

PUT /my_index/blogpost/1
{
  "title": "Nest eggs",
  "body":  "Making your money work...",
  "tags":  [ "cash", "shares" ],
  "comments": [  (1)
    {
      "name":    "John Smith",
      "comment": "Great article",
      "age":     28,
      "stars":   4,
      "date":    "2014-09-01"
    },
    {
      "name":    "Alice White",
      "comment": "More like this please",
      "age":     31,
      "stars":   5,
      "date":    "2014-10-22"
    }
  ]
}

因为所有的内容都在同一个文本里面,在查询的时候就没有必要拼接blog,因此检索性能会更好。

父子关联(Parent-Child Relationship)

 

 

 

 

 

 

 

 

 

 

 

 

 

© 著作权归作者所有

莫问viva
粉丝 41
博文 140
码字总数 116543
作品 0
长沙
高级程序员
私信 提问
Elastic 在年度用户大会 Elastic{ON} 2018 上发布众多新功能和技术预览

下载超过 2.25 亿次,Elastic 公开 X-Pack 源代码 旧金山 (Elastic{ON} 2018) – 2018 年 2 月 27 日 – Elastic,Elasticsearch 和 Elastic Stack背后的公司,今天宣布其产品累计下载次数达...

Medcl
2018/03/01
7
0
bboss v5.2.1 发布,Elasticsearch Rest Client

The best Elasticsearch Highlevel Rest Client API-----bboss v5.2.1 发布。 主要功能特色 ElasticSearch兼容性:2.x,5.x,6.x,+ JDK兼容性: jdk 1.7+ Spring boot兼容性:1.x,2.x ORM和DSL二......

bboss
2018/11/27
649
2
如何用 Node.js 和 Elasticsearch 构建搜索引擎

Elasticsearch 是一款开源的搜索引擎,由于其高性能和分布式系统架构而备受关注。本文将讨论其关键特性,并手把手教你如何用它创建 Node.js 搜索引擎。 Elasticsearch 概述 Elasticsearch 底...

oschina
2016/09/29
13.8K
6
Elasticsearch7.2中文文档翻译(一):Elasticsearch简介

Elasticsearch7.2系列文章:https://www.xugj520.cn/category/ES/![2019-07-17T09:38:26.png][1] 为了搜索和分析,你懂得!!! 简介 Elasticsearch是Elastic Stack核心的分布式搜索和分析引...

高效码农
07/24
82
0
spring-data-elasticsearch 基本案例详解(三)

『 风云说:能分享自己职位的知识的领导是个好领导。 』 运行环境:JDK 7 或 8,Maven 3.0+ 技术栈:SpringBoot 1.5+, Spring Data Elasticsearch 1.5+ ,ElasticSearch 2.3.2 本文提纲 一、...

夜黑人模糊灬
2018/05/13
951
1

没有更多内容

加载失败,请刷新页面

加载更多

最简单的获取相机拍照的图片

  import android.content.Intent;import android.graphics.Bitmap;import android.os.Bundle;import android.os.Environment;import android.provider.MediaStore;import andr......

MrLins
今天
4
0
说好不哭!数据可视化深度干货,前端开发下一个涨薪点在这里~

随着互联网在各行各业的影响不断深入,数据规模越来越大,各企业也越来越重视数据的价值。作为一家专业的数据智能公司,个推从消息推送服务起家,经过多年的持续耕耘,积累沉淀了海量数据,在...

个推
今天
8
0
第三方支付-返回与回调注意事项

不管是支付宝,微信,还是其它第三方支付,第四方支付,支付机构服务商只要涉及到钱的交易都要进行如下校验,全部成功了才视为成功订单 1.http请求是否成功 2.校验商户号 3.校验订单号及状态...

Shingfi
今天
4
0
简述Java内存分配和回收策略以及Minor GC 和 Major GC(Full GC)

内存分配: 1. 栈区:栈可分为Java虚拟机和本地方法栈 2. 堆区:堆被所有线程共享,在虚拟机启动时创建,是唯一的目的是存放对象实例,是gc的主要区域。通常可分为两个区块年轻代和年老代。更...

DustinChan
今天
6
0
Excel插入批注:可在批注插入文字、形状、图片

1.批注一直显示:审阅选项卡-------->勾选显示批注选项: 2.插入批注快捷键:Shift+F2 组合键 3.在批注中插入图片:鼠标右键点击批注框的小圆点【重点不可以在批注文本框内点击】----->调出批...

东方墨天
今天
6
1

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部