0、面向文档
应用中的对象很少只是简单的键值列表,更多时候它拥有复杂的数据结构,比如包含日期、地理位置、另一个对象或者数组。
总有一天你会想到把这些对象存储到数据库中。将这些数据保存到由行和列组成的关系数据库中,就好像是把一个丰富,信息表现力强的对象拆散了放入一个非常大的表格中:你不得不拆散对象以适应表模式(通常一列表示一个字段),然后又不得不在查询的时候重建它们。
Elasticsearch是面向文档(document oriented)的,这意味着它可以存储整个对象或文档(document)。然而它不仅仅是存储,还会索引(index)每个文档的内容使之可以被搜索。在Elasticsearch中,你可以对文档(而非成行成列的数据)进行索引、搜索、排序、过滤。这种理解数据的方式与以往完全不同,这也是Elasticsearch能够执行复杂的全文搜索的原因之一。
1、JSON
ELasticsearch使用Javascript对象符号(JavaScript Object Notation),也就是JSON,作为文档序列化格式。JSON现在已经被大多语言所支持,而且已经成为NoSQL领域的标准格式。它简洁、简单且容易阅读。
以下使用JSON文档来表示一个用户对象:
{"email": "john@smith.com","first_name": "John","last_name": "Smith","info": {"bio": "Eco-warrior and defender of the weak","age": 25,"interests": [ "dolphins", "whales" ]},"join_date": "2014/05/01"
}
尽管原始的user
对象很复杂,但它的结构和对象的含义已经被完整的体现在JSON中了,在Elasticsearch中将对象转化为JSON并做索引要比在表结构中做相同的事情简单的多。
2、索引(indexing)
我们首先要做的是存储员工数据,每个文档代表一个员工。在Elasticsearch中存储数据的行为就叫做索引(indexing),不过在索引之前,我们需要明确数据应该存储在哪里。
在Elasticsearch中,文档归属于一种类型(type),而这些类型存在于索引(index)中,我们可以画一些简单的对比图来类比传统关系型数据库:
Relational DB -> Databases -> Tables -> Rows -> Columns
Elasticsearch -> Indices -> Types -> Documents -> Fields
Elasticsearch集群可以包含多个索引(indices)(数据库),每一个索引可以包含多个类型(types)(表),每一个类型包含多个文档(documents)(行),然后每个文档包含多个字段(Fields)(列)。
你可能已经注意到索引(index)这个词在Elasticsearch中有着不同的含义,所以有必要在此做一下区分:
- 索引(名词) 如上文所述,一个索引(index)就像是传统关系数据库中的数据库,它是相关文档存储的地方,index的复数是indices 或indexes。
- 索引(动词) 「索引一个文档」表示把一个文档存储到索引(名词)里,以便它可以被检索或者查询。这很像SQL中的
INSERT
关键字,差别是,如果文档已经存在,新的文档将覆盖旧的文档。 - 倒排索引 传统数据库为特定列增加一个索引,例如B-Tree索引来加速检索。Elasticsearch和Lucene使用一种叫做倒排索引(inverted index)的数据结构来达到相同目的。
它不需要你做额外的管理操作,比如创建索引或者定义每个字段的数据类型。我们能够直接索引文档,Elasticsearch已经内置所有的缺省设置,所有管理操作都是透明的
3、搜索(search)
# 准备megacorp公司三个员工的数据
PUT /megacorp/employee/1
{"first_name" : "John","last_name" : "Smith","age" : 25,"about" : "I love to go rock climbing","interests": [ "sports", "music" ]
}PUT /megacorp/employee/2
{"first_name" : "Jane","last_name" : "Smith","age" : 32,"about" : "I like to collect rock albums","interests": [ "music" ]
}PUT /megacorp/employee/3
{"first_name" : "Douglas","last_name" : "Fir","age" : 35,"about": "I like to build cabinets","interests": [ "forestry" ]
}# 查询id:1的文档
GET /megacorp/employee/1# 搜索全部文档,默认情况下搜索会返回前10个结果
GET /megacorp/employee/_search# 搜索姓氏中包含“Smith”的员工
#轻量级的搜索方法,这种方法常被称作查询字符串(query string)搜索
GET /megacorp/employee/_search?q=last_name:Smith# 查询字符串搜索便于通过命令行完成特定(ad hoc)的搜索,但是它也有局限性。
# Elasticsearch提供丰富且灵活的查询语言叫做DSL查询(Query DSL),它允许你构建更加复杂、强大的查询。
# DSL(Domain Specific Language特定领域语言)以JSON请求体的形式出现。我们可以这样表示之前关于“Smith”的查询:
GET /megacorp/employee/_search
{"query" : {"match" : {"last_name" : "Smith"}}
}# 想要找到姓氏为“Smith”的员工,但是我们只想得到年龄大于30岁的员工。
# 我们的语句将添加过滤器(filter)
GET /megacorp/employee/_search
{"query" : {"bool" : {"filter" : {"range" : {"age" : { "gt" : 30 }}},"must" : {"match" : {"last_name" : "smith"}}}}
}# 全文搜索
# 搜索所有喜欢“rock climbing”的员工
# 传统数据库很难实现的功能
# 这个例子很好的解释了Elasticsearch如何在各种文本字段中进行全文搜索,并且返回相关性最大的结果集。
# 相关性(relevance)的概念在Elasticsearch中非常重要,而这个概念在传统关系型数据库中是不可想象的,
# 因为传统数据库对记录的查询只有匹配或者不匹配。
GET /megacorp/employee/_search
{"query" : {"match" : {"about" : "rock climbing"}}
}
# 短语搜索:确切的匹配若干个单词或者短语(phrases)
# 查询同时包含"rock"和"climbing"(并且是相邻的)的员工记录
GET /megacorp/employee/_search
{"query" : {"match_phrase" : {"about" : "rock climbing"}}
}
4、聚合(aggregations)。
Elasticsearch有一个功能叫做聚合(aggregations),它允许你在数据上生成复杂的分析统计。它很像SQL中的GROUP BY
但是功能更强大。
# 找到所有职员中最大的共同点(兴趣爱好)是什么:
GET /megacorp/employee/_search
{"aggs": {"all_interests": {"terms": { "field": "interests" }}}
}
Fielddata可以消耗大量的堆空间,特别是在加载高基数text字段时。一旦fielddata被加载到堆中,它将在该段的生命周期中保持在那里。此外,加载fielddata是一个昂贵的过程,可以导致用户体验延迟命中。这就是为什么fielddata默认是禁用的。如果您尝试对text 字段上的脚本进行排序,聚合或访问值,则会看到以下异常:
解决办法
# 您可以text使用PUT映射API在现有字段 上启用fielddata
PUT megacorp/_mapping/employee
{ "properties": { "interests": {"type":"text","fielddata":true } }
}
# 我们想知道所有姓"Smith"的人最大的共同点
GET /megacorp/employee/_search
{"size": 0,"query": {"match": {"last_name": "smith"}},"aggs": {"all_interests": {"terms": {"field": "interests"}}}
}# 聚合也允许分级汇总。例如,让我们统计每种兴趣下职员的平均年龄
# all_interests,avg_age是自定义的
GET /megacorp/employee/_search
{"aggs" : {"all_interests" : {"terms" : { "field" : "interests" },"aggs" : {"avg_age" : {"avg" : { "field" : "age" }}}}}
}
分级查询结果:
5、参考资料
- Elasticsearch 权威指南(中文版),本文内容基本来源于此网络文档;