本文仅是个人的学习笔记,有问题请指正。
在大数据领域,自从有了 Hadoop 以后,大家渐渐习惯收集日志到 HDFS 中,然后每天运行 MapReduce 任务做统计报表。但是,面对诸如“新上线的版本过去几分钟在各地反馈如何”,“昨天23:40左右这个投诉用户有没有异常”这种即时的开放性问题,传统的日志处理方案显得非常的笨拙和低效。复杂多变的实时数据分析需求,需要的是灵活快捷的响应处理,Elasticsearch的出现让这个问题得到了很好的解决!
Elasticsearch是一个基于Apache Lucene的实时分布式搜索和分析引擎。它让你以前所未有的速度处理大数据成为可能。
Elasticsearch以全文搜索、结构化搜索、分析或将这三者混合使用来提供强大的功能,目前已经有很多企业在使用它:
国外有Wikipedia、StackOverflow、Github、Facebook、Quora、LinkedIn、Netflix等公司都在使用Elasticsearch。
国内像百度、阿里巴巴、腾讯、新浪等公司都在使用
Elasticsearch,简单点理解,就是在Lucene的基础上封装了一层分布式架构,它有如下特点:
ElasticSearch把数据存放到一个或者多个索引中。如果用关系型数据库模型对比,索引的地位与数据库实例(Database)相当。索引存放和读取的基本单元是文档(Document)。ElasticSearch内部用Apache Lucene实现索引中数据的读写。要知道,在ElasticSearch中被视为单独的一个索引,在Lucene中可能不止一个。这是因为在分布式体系中,ElasticSearch会用到分片(shards)和备份(replicas)机制将一个索引存储多份。
在ElasticSearch的世界中,文档(Document)是主要的存在实体(在Lucene中也是如此)。所有的ElasticSearch应用需求到最后都可以统一建模成一个检索模型:检索相关文档。文档(Document)由一个或者多个域(Field)组成,每个域(Field)由一个域名(此域名非彼域名)和一个或者多个值组成(有多个值的值称为多值域(multi-valued))。在ElasticSeach中,每个文档(Document)都可能会有不同的域(Field)集合;也就是说文档(Document)是没有固定的模式和统一的结构。文档(Document)之间保持结构的相似性即可(Lucene中的文档(Document)也秉持着相同的规定)。实际上,ElasticSearch中的文档(Document)就是Lucene中的文档(Document)。从客户端的角度来看,文档(Document)就是一个JSON对象(关于JSON格式的相关信息,请参看hhtp://en.wikipedia.org/wiki/JSON)。
每个文档在ElasticSearch中都必须设定它的类型。文档类型使得同一个索引中在存储结构不同文档时,只需要依据文档类型就可以找到对应的参数映射(Mapping)信息,方便文档的存取。
单独一个ElasticSearch服务器实例称为一个节点。对于许多应用场景来说,部署一个单节点的ElasticSearch服务器就足够了。但是考虑到容错性和数据过载,配置多节点的ElasticSearch集群是明智的选择。
集群是多个ElasticSearch节点的集合。这些节点齐心协力应对单个节点无法处理的搜索需求和数据存储需求。集群同时也是应对由于部分机器(节点)运行中断或者升级导致无法提供服务这一问题的利器。ElasticSearch提供的集群各个节点几乎是无缝连接(所谓无缝连接,即集群对外而言是一个整体,增加一个节点或者去掉一个节点对用户而言是透明的<个人理解,仅供参考>)。在ElasticSearch中配置一个集群非常简单,在我们看来,这是在与同类产品中竞争所体现出的最大优势。
前面已经提到,集群能够存储超出单机容量的信息。为了实现这种需求,ElasticSearch把数据分发到多个存储Lucene索引的物理机上。这些Lucene索引称为分片索引,这个分发的过程称为索引分片(Sharding)。在ElasticSearch集群中,索引分片(Sharding)是自动完成的,而且所有分片索引(Shard)是作为一个整体呈现给用户的。需要注意的是,尽管索引分片这个过程是自动的,但是在应用中需要事先调整好参数。因为集群中分片的数量需要在索引创建前配置好,而且服务器启动后是无法修改的,至少目前无法修改。
通过索引分片机制(Sharding)可以向ElasticSearch集群中导入超过单机容量的数据,客户端操作任意一个节点即可实现对集群数据的读写操作。当集群负载增长,用户搜索请求阻塞在单个节点上时,通过索引副本(Replica)机制就可以解决这个问题。索引副本(Replica)机制的的思路很简单:为索引分片创建一份新的拷贝,它可以像原来的主分片一样处理用户搜索请求。同时也顺便保证了数据的安全性。即如果主分片数据丢失,ElasticSearch通过索引副本使得数据不丢失。索引副本可以随时添加或者删除,所以用户可以在需要的时候动态调整其数量。
在运行的过程中,ElasticSearch会收集集群的状态、索引的参数等信息。这些数据被存储在Gateway中。
curl -XPUT 'http://localhost:9200/{index}/{type}/{id}' -d
'{
"field" : "content",
...
}'
在插入的过程中index会自动创建,一个Doc由_index
、_type
、_id
唯一指定(如果不指定ID,则会自动生成)。另外,在插入的过程中可以通过?version=
、?timestamp=
、?ttl=
指定一些参数。具体参看《Index API》
一个Document是由_index
、_type
、_id
三个属性唯一标识。
curl -XGET 'http://localhost:9200/website/blog/001'
还可以通过/_source
只显示Doc的内容:
curl -XGET 'http://localhost:9200/website/blog/1/_source'
{
"title": "My first blog entry",
"text": "Just trying this out...",
"date": "2014/01/01"
}
pretty
在任意的查询字符串中增加pretty参数。会让Elasticsearch美化输出JSON结果以便更加容易阅读
curl -XDELETE 'http://localhost:9200/twitter/tweet/1'
执行PUT操作,如果已经存在,就相当于更新操作:
curl -XPUT 'http://localhost:9200/website/blog/001' -d
'{ "field": "value", ... }'
可以看到输出结果:
{
"_index": "website",
"_type": "blog",
"_id": "001",
"_version": 2,
"created": false }
created: false
创建失败, 是因为已经存在指定文档。
在内部,Elasticsearch已经标记旧文档为删除并添加了一个完整的新文档。旧版本文档不会立即消失,但你也不能去访问它。Elasticsearch会在你继续索引更多数据时清理被删除的文档。
$ curl -i -XHEAD 'http://localhost:9200/website/blog/001'
HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
Content-Length: 0
Multi Get使用关键字_mget
,可以一次获取多个文档,而且这些文档可以跨索引、跨类型。
curl 'localhost:9200/_mget' -d '{ "docs" : [ { "_index" : "INDEX1", "_type" : "type", "_id" : "3" }, { "_index" : "INDEX2", "_type" : "type", "_id" : "1" } ] }'
curl 'localhost:9200/{index}/_mget' -d '{ "docs" : [ { "_type" : "type", "_id" : "1" }, { "_type" : "type", "_id" : "2" } ] }'
curl 'localhost:9200/{index}/{type}/_mget' -d '{
"ids" : ["1", "2"]
}'
Bulk API使用关键字_bulk
,允许我们通过一次请求来实现多个文档的create、index、update或delete。
bulk的请求结构如下:
{ action: { metadata }}\n
{ request body }\n
{ action: { metadata }}\n
{ request body }\n
...
加入我们把一个批量请求写在一个文件bulk_format
中:
{"create":{"_index":"website","_type":"blog","_id":"004"}}
{"title":"The Hero","text":"I have been watching the TV Series...","date":"2015/09/11"}
{"delete":{"_index":"website","_type":"blog","_id":"001"}}
执行批量请求(--data-binary
保留换行符):
$ curl -s -XPOST localhost:9200/_bulk --data-binary @bulk_format
$ curl -XPUT 'http://localhost:9200/twitter/'
$ curl -XPUT 'http://localhost:9200/twitter/' -d '{ "settings" : { "number_of_shards" : 3, "number_of_replicas" : 2 } }'
curl -XPUT localhost:9200/test -d '{ "settings" : { "number_of_shards" : 1 }, "mappings" : { "type1" : { "_source" : { "enabled" : false }, "properties" : { "field1" : { "type" : "string", "index" : "not_analyzed" } } } } }'
$ curl -XDELETE 'http://localhost:9200/twitter/'
$ curl -XGET localhost:9200/movie
$ curl -XGET localhost:9200/movie/_aliases
$ curl -XGET localhost:9200/movie/_mapping
$ curl -XGET localhost:9200/movie/_setting
Get到的是索引的aliases
、mappings
、setting
等信息。
关闭一个索引之后,将不能read/write。
curl -XPOST 'localhost:9200/my_index/_close'
curl -XPOST 'localhost:9200/my_index/_open'
ElasticSearch中的检索主要分为两类:确切值、全文检索
_score
。在Elasticsearch中,每一个字段的数据都是默认被索引的,用于快速检索。字段是否被索引由"index"
参数控制,它的取值有三个:
值 | 解释 |
---|---|
analyzed | 首先分析这个字符串,然后索引。换言之,以全文形式索引此字段。 |
not_analyzed | 索引这个字段,使之可以被搜索,但是索引内容和指定值一样。不分析此字段。 |
no | 不索引这个字段。这个字段不能为搜索到。 |
string
类型字段默认值是analyzed
,用于全文检索。其他简单类型——long
、double
、date
等只能取no
和not_analyzed
,它们的值不能被分析。
对于string型字段,在被分析之后,所得的结果(单词)会用来建立倒排索引。在进行检索时,检索字符串也会经过相同的分析器,然后用所得的结果在倒排索引中进行匹配,匹配的越多相关性_score
打分越高。
$ curl -XGET 'localhost:9200/_analyze?analyzer=standard&pretty' -d 'The quick brown foxes jumped over the lazy dog'
搜索的关键字是_search
,我们可以跨索引、跨类型进行搜索(假设gb
,us
是索引,user
,tweet
是类型):
/_search # 在所有索引的所有类型中搜索
/gb/_search # 在索引gb的所有类型中搜索
/gb,us/_search # 在索引gb和us的所有类型中搜索
/g*,u*/_search # 在以g或u开头的索引的所有类型中搜索
/gb/user/_search # 在索引gb的类型user中搜索
/gb,us/user,tweet/_search # 在索引gb和us的类型为user和tweet中搜索
/_all/user,tweet/_search # 在所有索引中的搜索类型user和tweet的文档
利用字符串查询
通过查询字符串进行搜索就是 通过HTTP参数传递查询的关键字:
$ curl -XGET localhost:9200/movie/_search?q=runtime:90
fieldName:desc/asc
利用DSL查询(结构化查询语句)
所谓结构化查询语句是指通过JSON请求体来指定查询条件。
curl -XGET localhost:9200/movie/info/_search -d '{ "query": { "term": { "runtime": 90 } } }'
Elasticsearch检索分为两部分:Query 和 Filter。两者的区别在于:filter是不计算相关性的,同时可以cache。因此,filter速度要快于query。
常用的查询过滤语句:
query:
"query"
和 "filter"
子句。must
(相当于AND
),must_not
(相当于NOT
),should
(相当于OR
)。filter:
假设有一个索引 movie 存储了一组电影相关信息,格式如下:
{
"name": "Avengers: Age of Ultron",
"rating": 7.8,
"description": "When Tony Stark and Bruce Banner try to jump-start a dormant peacekeeping...",
"stars": ["Joss Whedon","Robert Downey Jr","Chris Evans","Mark Ruffalo"],
"type": ["Action","Adventure","Sci-Fi"],
"runtime": 141 }
$ curl 'localhost:9200/movie/_search?fields=aggregations&pretty' -d ' { "aggs" : { "min_runtime": { "min" : { "field":"runtime" } } } }'
curl 'localhost:9200/movie/_search?fields=aggregations&pretty' -d ' { "aggs" : { "max_rating": { "max" : { "field":"rating" } } } }'
curl 'localhost:9200/movie/_search?fields=aggregations&pretty' -d ' { "aggs" : { "intraday_return": { "sum" : { "field":"runtime" } } } }'
curl 'localhost:9200/movie/_search?fields=aggregations&pretty' -d ' { "aggs" : { "avg_rating": { "avg" : { "field":"rating" } } } }'
curl 'localhost:9200/movie/_search?fields=aggregations&pretty' -d ' { "aggs" : { "ratings_stats": { "stats" : { "field":"rating" } } } }'
curl 'localhost:9200/movie/_search?fields=aggregations&pretty' -d ' { "aggs" : { "runtime_products": { "filter":{"term":{"runtime":90}}, "aggs" : { "avg_rating":{ "avg":{"field":"rating"} } } } } }'
curl 'localhost:9200/movie/_search?fields=aggregations&pretty' -d ' { "aggs" : { "types": { "terms" : { "field":"type" } } } }'
curl 'localhost:9200/movie/_search?fields=aggregations&pretty' -d ' { "aggs" : { "rating_ranges": { "range" : { "field":"rating", "ranges":[ {"to":3}, {"from":3,"to":5}, {"from":5,"to":8}, {"from":8,"to":10} ] } } } }'
curl 'localhost:9200/movie/_search?fields=aggregations&pretty' -d ' { "aggs" : { "ratings": { "histogram" : { "field":"rating", "interval":3 } } } }'
cluster级别的API总是以http://localhost:9200/_cluster/
开头。
6.1.1、查看集群 health 状态
curl -XGET 'http://localhost:9200/_cluster/health?pretty'
#也可以查看某个索引的 health 状态:
curl -XGET 'http://localhost:9200/_cluster/health/movie'
6.1.2、查看集群state
curl -XGET 'http://localhost:9200/_cluster/state'
该命令会输出所有的nodes和shards的状态信息,但是由于太多,可读性不高。
6.1.3. 查看集群的stats
$ curl -XGET localhost:9200/_cluster/stats
统计信息包括shards、nodes、docs、store、还有操作系统CPU、内存、进程、JVM、文件系统等相关统计信息。
6.1.4. 查看节点的stats
curl -XGET 'http://localhost:9200/_nodes/stats'
6.1.5. 查看节点信息
curl -XGET 'http://localhost:9200/_nodes'
ElasticSearch提供了_cat
命令用以格式化输出,将JSON结果以列表的形式输出。
输出集群健康状态:
$ curl 'localhost:9200/_cat/health'
输出当前的master节点:
$ curl 'localhost:9200/_cat/master'
输出所有的nodes信息:
$ curl 'localhost:9200/_cat/nodes'
输出所有doc数:
$ curl 'localhost:9200/_cat/count'
输出索引别名:
$ curl 'localhost:9200/_cat/aliases?v'
输出所有索引的状态和统计数据:
$ curl 'localhost:9200/_cat/indices'
输出每个节点的shards分配情况:
$ curl 'localhost:9200/_cat/allocation'
输出每个shard的统计信息:
$ curl 'localhost:9200/_cat/shards'
输出当前recovery的进度:
$ curl 'localhost:9200/_cat/recovery'
6.3.1、重定向(reroute)
重定向是指手动控制shard的分布,包括三种操作:
$ curl -XPOST 'localhost:9200/_cluster/reroute' -d ' {"commands":[{ "move":{ "index":"movie", "shard":2, "from_node":"eng1.lycc.eseng2.09", "to_node":"eng1.lycc.eseng2.08" } }] }'
6.3.2、关闭(shutdown)
关闭所有节点
curl -XPOST 'http://localhost:9200/_shutdown'
关闭指定节点
curl -XPOST 'http://localhost:9200/_cluster/nodes/nodeId1,nodeId2/_shutdown'
延迟关闭
curl -XPOST 'http://localhost:9200/_cluster/nodes/_local/_shutdown?delay=10s'
个人站点:http://songlee24.github.com