handling relatioships
现实世界里,关系(relationship)是尤其重要的:博客文章包含评论,银行账号有相应的交易,顾客有银行账户,订单也由订单线,而目录则包含文件和子目录。
关系数据库便以此而设计——下面这些描述对你来说也并不陌生:
- 每个实体(entity,或者行 row)可以由一个主键唯一识别
- 实体都是正规化了的。对唯一实体的数据只会存储以此,相关的实体则只需要存储其主键。改变实体的数据只会出现在一个地方
- 实体在查询的时候可以被join从而支持多个实体的交叉查询
- 大多数的关系型数据库支持在多个实体上的ACID事务
但是关系型数据库除了不支持全文检索外还拥有自身的缺陷。在查询时进行join常常耗资源。依赖不同的硬件执行实体的join不实用。这也就给存放在一个服务器上的数据量造成了一个限制。
ES,如同大多数的NoSQL数据库,就将显示世界看做是扁平的。index 就是独立的文档的扁平集合。单一的文档应当包含确定其被搜索请求命中所需的信息。
改变ES中的单一文档的数据是ACID的,包含多个文档的事务却不是。没有办法使得可以保证事务的正常回滚。
扁平世界的优点;
- 索引快速且无锁
- 搜索快速且无锁
- 海量数据可以分布在若干节点上,因为每个文档都是独立于其他文档。
然而关系也是重要的。我们需要消除扁平世界和真实世界的隔阂。在 ES 中,四种通用的技术用来管理关系型数据:
- Application-side joins
- Data denormalization
- Nested objects
- Parent/Child relationships
而最终的解决方案需要这些技术的混合。
Application-side joins
我们可以部分地通过在应用中实现 join 模拟关系型数据库。例如,我们在索引用户和用户的博客文章。在关系型世界中,我们可以做下面的动作:
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": 1
}
index
,type
,id
整体作为主键blogpost
通过存放用户的id
与用户相连。index
和type
因为他们在应用中硬编码所以并没有强制。
在博客文章中查询用户ID为1
的就很简单了:
GET /my_index/blogpost/_search
{
"query": {
"filtered": {
"filter": {
"term": { "user": 1 }
}
}
}
}
查询用户名是 John 的博客文章,我们需要运行两个查询:第一个查找所有叫做John的用户得到他们的ID,第二步将这些ID传入一个查询中获得作者为John的文章
GET /my_index/user/_search
{ "query": { "match": { "name": "John" } }}
GET /my_index/blogpost/_search
{ "query": { "filtered": { "filter": { "terms": { "user": [1] } } } } }
在terms
过滤器中的值就是从第一个查询中得到的结果。
application-side join的主要好处就是数据的正规化。改变用户的名字只会在一个地方:user
文档。而其弱点就是你需要执行额外的查询在搜索时进行join。
这个例子中,只有一个用户匹配了我们第一查询,但是在现实情形下,我们常常会碰到百万个以John为名的用户。包含所有这些 ID 在第二个查询中就产生了一个巨大的查询,包含数百万的term检索。
这个场景适用于第一个搜索结果比较小的情形,并且最好他们基本不变化。这就使得ES可以缓存结果避免频繁执行第一个查询。
Data denormalization
从ES获得最佳搜索性能的方法就是通过在索引时的去正规化数据。对每个需要获取的文档保持冗余的拷贝将会去除join的需要。
如果我们希望通过作者名找到博客文章,包含这个用户的名字在该博客文章文档本身即可:
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"
}
}
现在,我们既可以通过单个查询找到作者为John
的文章了。
GET /my_index/blogpost/_search
{
"query": {
"bool": {
"must": [
{ "match": { "title": "relationships" }},
{ "match": { "user.name": "John" }}
]
}
}
}
data denormalization 的优势是速度。因为每个文档包含需要确定是否满足查询的所有的信息,也就避免了额外的 join。
Field collapsing
一般要求是用一个特定的字段的 group 来展现搜索结果。我们可能希望返回最相关的博客文章,而使用用户名进行group。根据用户名进行group就代表着对 terms
聚合的要求。为了对用户的全名进行 group,name 字段就应被设置成 not_analyzed
形式,正如在 聚合和分析 中解释的那样:
PUT /my_index/_mapping/blogpost
{
"properties": {
"user": {
"properties": {
"name": {
"type": "string",
"fields": {
"raw": {
"type": "string",
"index": "not_analyzed"
}
}
}
}
}
}
}
user.name
字段用作全文检索user.name.raw
字段用作terms
聚合
然后添加一些数据:
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"
}
}
PUT /my_index/user/3
{
"name": "Alice John",
"email": "alice@john.com",
"dob": "1979/01/04"
}
PUT /my_index/blogpost/4
{
"title": "Relationships are cool",
"body": "It's not complicated at all...",
"user": {
"id": 3,
"name": "Alice John"
}
}
现在我们就可以执行一个查询relationships
的博客文章了,作者名为John
,并使用作者名进行group,使用top_hits
聚合
GET /my_index/blogpost/_search?search_type=count
{
"query": {
"bool": {
"must": [
{ "match": { "title": "relationships" }},
{ "match": { "user.name": "John" }}
]
}
},
"aggs": {
"users": {
"terms": {
"field": "user.name.raw",
"order": { "top_score": "desc" }
},
"aggs": {
"top_score": { "max": { "script": "_score" }},
"blogposts": { "top_hits": { "_source": "title", "size": 5 }}
}
}
}
}
我们感兴趣的博客文章返回在
blogposts
聚合,所以我们可以通过设置search_type=count
来关闭常用的搜索hits
.query
返回用户为John
的关于relationships
博客文章terms
聚合对每个user.name.raw
值创建了一个桶top_score
聚合将在users
聚合中的项进行按桶的排序top_hits
聚合返回对每个用户前5个相关文章
上面查询的简化结果如下:
...
"hits": {
"total": 2,
"max_score": 0,
"hits": []
},
"aggregations": {
"users": {
"buckets": [
{
"key": "John Smith",
"doc_count": 1,
"blogposts": {
"hits": {
"total": 1,
"max_score": 0.35258877,
"hits": [
{
"_index": "my_index",
"_type": "blogpost",
"_id": "2",
"_score": 0.35258877,
"_source": {
"title": "Relationships"
}
}
]
}
},
"top_score": {
"value": 0.3525887727737427
}
},
...
hits
数组为空,因为我们设置了search_type = count
对每个用户都有一个桶
在每个用户的桶下面都有一个blogposts.hits
的数组包含了对那个用户的前列的结果
在每个用户的桶内是按照相关度进行排序的
使用top_hits
聚合等价于执行查询返回用户的名字以及相应最为相关的博客文章,接着对每个用户执行同样地查询,来获得相应最相关的博客文章。但是更加高效。
在每个桶中返回的前面几条记录是执行一个基于原初主查询的微型查询的结果。这个微查询支持常用的特征,可以通过高亮和分页的特征。
Nested objects
Parent/Child relationships
http://blog.csdn.net/dm_vincent/article/details/47710367
http://blog.csdn.net/dm_vincent/article/details/47710591
相关推荐
Elasticsearch数据导出工具是一种高效实用的解决方案,它允许用户方便地从Elasticsearch(ES)集群中抽取数据,并将其导出到不同的目标,如MySQL数据库或本地文件系统。这款工具尤其适用于需要进行数据迁移、备份或...
在Linux环境下,命令为`/opt/es/essoftware/elasticsearch-2.3.4/bin/elasticsearch`。 4. 服务启动成功后,可以在浏览器中输入`http://cm3:9200/`来验证Elasticsearch是否正常运行。 二、Elasticsearch的管理工具 ...
索引是Elasticsearch中的逻辑存储单元,类似于关系数据库中的表。 3. **序列化与反序列化**: 使用Nest库,对象会被自动转换为JSON格式,发送到Elasticsearch进行索引。查询结果也会被反序列化回.NET对象。 4. **...
"es搜索引擎"标签进一步确认了我们正在处理一个与Elasticsearch相关的项目,Elasticsearch通常用于处理大规模数据的搜索和分析任务。 **文件名称列表详解:** 1. **.classpath** - 这是一个Eclipse项目文件,包含...
在Elasticsearch SQL中,INSERT用于向索引中添加新的文档,这类似于在关系型数据库中插入新记录。UPDATE则用于修改已存在的文档,而DELETE语句则可以用来从索引中移除特定的文档。这些操作的引入使得Elasticsearch在...
在Java开发中,我们通常会创建一个专门的工具类来处理Elasticsearch相关的操作,以便更好地管理和控制数据。 在描述中提到,这个工具类支持通过标签注释实体类。这意味着开发者可以使用特定的注解(如@Document、@...
2. 配置:在Elasticsearch的配置文件`elasticsearch.yml`中添加IK插件的配置,例如设置默认分词器、启用扩展词典等。 3. 启动:重启Elasticsearch服务以使配置生效。 4. 测试:通过Elasticsearch的API进行测试,...
此外,Elasticsearch还可以处理文档之间的关系,这对于构建复杂的数据结构和实现复杂查询非常有用。 在本书的最后部分,作者将指导读者如何优化Elasticsearch的性能,确保其在生产环境中的高效运行。这对于负责管理...
在IT领域,尤其是在搜索引擎优化和大数据分析中,Elasticsearch(ES)是一个广泛使用的开源全文检索引擎。它基于Lucene库,提供了分布式、实时、高可用性以及容错能力的数据存储和搜索解决方案。本篇文章将重点讲解...
4. **类型(Type)**:在Elasticsearch 7.x及以后的版本中被弃用,之前的版本中每个索引可以包含多个类型。 5. **分片(Shard)**:为了分散存储和提高查询效率,Elasticsearch将索引分成多个分片。分片可以在不同节点...
在Elasticsearch中,索引(Index)是数据的容器,类似于关系数据库中的数据库。文档(Document)是存储在索引中的基本单位,它是JSON格式的数据对象。类型(Type)原本用于区分索引中的不同数据类型,但在最新版本中...
在单机环境中部署ElasticSearch相对简单,只需下载并解压ElasticSearch软件包即可运行。这种方式适合于测试和开发环境。 **2.2. 服务器环境** 在生产环境中部署ElasticSearch时,通常会采用集群架构。这种情况下,...
2. **索引(Index)**:索引是Elasticsearch中的数据容器,类似于关系数据库中的数据库。你可以创建一个或多个索引来存储不同类型的数据。 3. **类型(Type)**:在Elasticsearch 6.x版本中,已经被废弃,但在6.8.9中...
- 插件的安装通常通过`bin/elasticsearch-plugin`命令行工具进行,添加指定的分词器到Elasticsearch配置中。 6. **数据操作:** - 使用`curl`命令或客户端(如Java API)向Elasticsearch发送HTTP请求来创建、更新...
6. **分片(Shard)**:索引可以被分成多个分片,分片是Elasticsearch处理大量数据的方式,允许水平扩展。 7. **副本(Replica)**:每个分片都可以有副本,用于提高数据冗余和故障恢复。 **Elasticsearch 7.14.2 版本...
Elasticsearch 6.5.4 是一个高度可扩展的开源全文搜索引擎,它基于 Lucene 构建,设计用于在分布式环境中提供快速、可靠且可伸缩的数据存储和搜索服务。这个版本专为 Windows 操作系统优化,允许用户在 Windows 平台...
在 ELK 技术栈(Elasticsearch, Logstash, Kibana)中,Elasticsearch 负责存储和索引日志数据,SpringBoot 是一个流行的 Java 应用开发框架,它们经常一起用于企业级的日志管理和分析系统。 **1. Elasticsearch ...
ElasticSearch是Elastic产品栈的核心组件,与Logstash(数据收集和处理)、Kibana(数据可视化)和Beats(轻量级数据发送代理)等一起,构成了一套全面的数据解决方案。 **为什么选择ElasticSearch?** 传统的...
在 Elasticsearch 中,IK Analyzer 可以帮助我们更好地处理中文文档,确保搜索引擎可以正确理解和索引中文文本。IK Head 插件是用于图形化查看 IK Analyzer 分词结果的工具,它提供了友好的界面,便于开发者调试和...