本篇文档首先向大家简单介绍下 ES,然后介绍它的存储形式,以及如何使用查询。对比相当于 MySQL 数据库的表结构和 SQL 语句。本篇文章并不涉及底层原理,仅仅介绍如何使用。
ElasticSearch 介绍
ES 是基于 Java 语言进行开发,它的内部使用 Lucene 做索引与搜索,但是它的目的是使全文检索变得简单,通过隐藏 Lucene 的复杂性,取而代之的提供一套简单一致的 RESTful API。
Elasticsearch 不仅仅是 Lucene,并且也不仅仅只是一个全文搜索引擎。 它可以被下面这样准确的形容:
- 一个分布式的实时文档存储,每个字段 可以被索引与搜索
- 一个分布式实时分析搜索引擎
- 能胜任上百个服务节点的扩展,并支持 PB 级别的结构化或者非结构化数据
数据存储
基本概念介绍
document
文档可以对应为数据库中的一行数据,ES 使用 JSON 作为文档的序列化格式,大多数的编程语言都支持序列化,下面这个 JSON 文档代表一个 user 对象。
js
{
"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"
}
index
如何将上面的用户对象存储到 ES 集群中,首先要确定存储的位置,存储的位置就是索引,索引就相当于数据库。
一个Elasticsearch集群可以包含多个索引 ,相应的每个索引可以包含多个类型 。这些不同的类型存储着多个文档 ,每个文档还有多个属性。
basic
curl -XPUT 'localhost:9200/customer/external/1?pretty&pretty' -d'
{
"name": "John Doe"
}'
- customer: 索引名称
- external: 类型名称
- 1: 特定的客户 ID
请求之后的响应结构如下所示:
js
{
"_index":"customer",
"_type":"external",
"_id":"1",
"_version":1,
"result":"created",
"_shards":**{
"total":2,
"successful":1,
"failed":0
},
"created":true
}
字段类型
ES 中可以指定字段为两种类型,分别为 keyword 和 text。keyword 不支持分词,进行完全匹配。text 字段进行分词,适用于后续的全文索引。
指定字段类型时分为三步,分别是创建索引、定义字段类型和添加数据。其中通过索引映射(Index Mapping)来定义字段类型。如下所示,指定 title 字段为 text 类型。
js
PUT /my-index
{
"mappings":{
"properties":{
"title":{
"type":"text"
}
}
}
}
数据查询
基本查询
上文中,我们将数据存储到 ES 中,下面我们演示下如何搜索到存储的数据
basic
curl -XGET 'localhost:9200/customer/external/1?pretty&pretty'
{
"name": "John Doe"
}'
点击查看返回数据
json
{
"_index" : "customer",
"_type" : "external",
"_id" : "1",
"_version" : 1,
"found" : true,
"_source" : { "name": "John Doe" }
}
在返回的 source 字段中,包含了全部的 customer 索引下的文档。除了上面的基本查询,返回全部的数据之外,我们再看下其他的查询请求,请求参数分别在浏览器 url 中和 body 中,其返回的数据不变
basic
// 请求参数在 url 中
curl -XGET 'localhost:9200/bank/_search?q=*&sort=account_number:asc&pretty'
// 请求参数在 body 中
curl -XGET 'localhost:9200/bank/_search?pretty' -d'
{
"query": { "match_all": {} },
"sort": [
{ "account_number": "asc" }
]
}'
- bank: 是指查询的索引
- q=* : 返回索引中所有的文档
- pretty: 告诉 ES 返回漂亮的 JSON 数据
点击查看返回数据
ruby
{
"took":63,
"timed_out":false,
"_shards":**{
"total":5,
"successful":5,
"failed":0
},
"hits":**{
"total":1000,
"max_score":null,
"hits":**[
**{
"_index":"bank",
"_type":"account",
"_id":"0",
"sort":**[
0
],
"_score":null,
"_source":**{
"account_number":0,
"balance":16623,
"firstname":"Bradshaw",
"lastname":"Mckenzie",
"age":29,
"gender":"F",
"address":"244 Columbus Place",
"employer":"Euron",
"email":"bradshawmckenzie@euron.com",
"city":"Hobucken",
"state":"CO"
}
},
**{
"_index":"bank",
"_type":"account",
"_id":"1",
"sort":**[
1
],
"_score":null,
"_source":**{
"account_number":1,
"balance":39225,
"firstname":"Amber",
"lastname":"Duke",
"age":32,
"gender":"M",
"address":"880 Holmes Lane",
"employer":"Pyrami",
"email":"amberduke@pyrami.com",
"city":"Brogan",
"state":"IL"
}
},
...
]
}
}
返回的数据部分参数释义如下所示:
- took - Elasticsearch 执行搜索的时间(毫秒)
- time_out - 告诉我们搜索是否超时
- _shards - 告诉我们多少个分片被搜索了,以及统计了成功/失败的搜索分片
- hits - 搜索结果
- hits.total - 搜索结果
- hits.hits - 实际的搜索结果数组(默认为前 10 的文档)
- sort - 结果的排序 key (键)(没有则按 score 排序)
- score 和max_score -现在暂时忽略这些字段
Query DSL
Elasticsearch 提供了一个可以执行查询的 Json 风格的 DSL (domain-specific language 领域特定语言)。这个被称为 Query DSL。如下所示,将介绍基本的查询参数。
basic
curl -XGET 'localhost:9200/bank/_search?pretty' -d'
{
"query": { "match": { "account_number": 20 } },
"from": 10,
"size": 10,
"sort": { "balance": { "order": "desc" } },
"_source": ["account_number", "balance"]
}'
- query: query 参数传递的参数为 match_all 代表的是返回索引下全部的文档, account_number:20 代表返回账号为 20 的文档。
- from: 返回这个索引的第 11 条数据到第 20 条数据。
- size: 返回数据大小,默认为 10 条数据
- sort: 对账户余额做降序排序
- source: 返回数据只包含 account_number 和 balance 两个字段
在 match 中,我们可以指定字段必须满足两个条件 / 满足其中一个条件 / 即满足一个条件但并不满足另外一个条件,查询如下所示:
css
// address 中包含 mill 或者 lane
curl -XGET 'localhost:9200/bank/_search?pretty' -d'
{
"query": { "match": { "address": "mill lane" } }
}'
// address 中包含 mill 和 lane
curl -XGET 'localhost:9200/bank/_search?pretty' -d'
{
"query": {
"bool": {
"must": [
{ "match": { "address": "mill" } },
{ "match": { "address": "lane" } }
]
}
}
}'
// address 中包含 mill 或者 lane
curl -XGET 'localhost:9200/bank/_search?pretty' -d'
{
"query": {
"bool": {
"should": [
{ "match": { "address": "mill" } },
{ "match": { "address": "lane" } }
]
}
}
}'
// 找出账户余额 20000 至 30000 的数据
curl -XGET 'localhost:9200/bank/_search?pretty' -d'
{
"query": {
"bool": {
"must": { "match_all": {} },
"filter": {
"range": {
"balance": {
"gte": 20000,
"lte": 30000
}
}
}
}
}
}'
// 执行聚合,以下相当于
curl -XGET 'localhost:9200/bank/_search?pretty' -d'
{
"size": 0,
"aggs": {
"group_by_state": {
"terms": {
"field": "state.keyword"
}
}
}
}'
相当于 SQL:
SELECT state, COUNT(*) FROM bank GROUP BY state ORDER BY COUNT(*) DESC
- bool must 语句指定了所有查询必须为 true 时将匹配到文档
- bool should 语句指定了一个查询列表,两者中的一个为 true 时将匹配到文档
- bool must_not 语句指定了一个查询列表,都不为 true 将匹配到文档
客户端类库推荐
使用Java High Level REST Client操作elasticsearch
目前本人就职于知乎,后续想写一篇本人的职场经历(从 17 年至今)。点赞超过 20 就开一篇小说😄。