您的位置:首页 > 其它

Elasticsearch简介

2016-07-07 11:34 239 查看

Elasticsearch简介

Elasticsearch是一个实时分布式搜索和分析引擎。它让你以前所未有的速度处理大数据成为可能。

使用场景

全文检索

结构化搜索

分析

应用

维基百科使用Elasticsearch提供全文搜索并高亮关键字,以及输入实时搜索(search-as-you-type)和搜索纠错(did-youmean)等搜索建议功能。

英国卫报使用Elasticsearch结合用户日志和社交网络数据提供给他们的编辑以实时的反馈,以便及时了解公众对新发表的文章的回应。

StackOverflow结合全文搜索与地理位置查询,以及more-like-this功能来找到相关的问题和答案。

Github使用Elasticsearch检索1300亿行的代码。

Elasticsearch vs Lucene

Lucene只是一个库。想要使用它,你必须使用Java来作为开发语言并将其直接集成到你的应用中,更糟糕的是,Lucene非常复杂,你需要深入了解检索的相关知识来理解它是如何工作的。Elasticsearch也使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的 RESTfulAPI 来隐藏Lucene的复杂性,从而让全文搜索变得简单。

与Elasticsearch交互

Elasticsearch为Java用户提供了两种内置客户端

节点客户端(node client)

节点客户端以无数据节点(none data node)身份加入集群,换言之,它自己不存储任何数据,但是它知道数据在集群中的具体位置,并且能够直接转发请求到对应的节点上。

传输客户端(Transport client)

这个更轻量的传输客户端能够发送请求到远程集群。它自己不加入集群,只是简单转发请求给集群中的节点。

两个Java客户端都通过9300端口与集群交互,使用Elasticsearch传输协议(Elasticsearch Transport Protocol)。集群中的节点

之间也通过9300端口进行通信。如果此端口未开放,你的节点将不能组成集群。

注意:Java客户端所在的Elasticsearch版本必须与集群中其他节点一致,否则,它们可能互相无法识别。

向Elasticsearch发出的请求的组成部分与其它普通的HTTP请求是一样的:

curl -X<VERB> '<PROTOCOL>://<HOST>/<PATH>?<QUERY_STRING>' -d '<BODY>'


VERB表示HTTP方法,例如: GET,POST,PUT,HEAD,DELETE

PROTOCOL表示http或者https协议(只有在Elasticsearch前面有https代理的时候可用)

HOST表示Elasticsearch集群中的任何一个节点的主机名,如果是在本地的节点,那么就叫localhost

PORT表示Elasticsearch HTTP服务所在的端口,默认为9200

QUERY_STRING表示一些可选的查询请求参数,例如 ?pretty 参数将使请求返回更加美观易读的JSON数据

BODY表示request body,一个JSON格式的请求主体(如果请求需要的话)

关系型数据库 vs Elasticsearch

Relational DB -> Databases -> Tables -> Rows -> Columns
Elasticsearch -> Indices(好比数据库) -> Types(好比表) -> Documents(好比记录) -> Fields(好比列)


集群内部工作方式

集群健康:green、yellow或者red

GET /_cluster/health

{
"cluster_name": "elasticsearch",
"status": "green", <1>
"timed_out": false,
"number_of_nodes": 1,
"number_of_data_nodes": 1,
"active_primary_shards": 0,
"active_shards": 0,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 0
}


颜色意义
green所有主要分片和复制分片都可用
yellow所有主要分片可用,但不是所有复制分片都可用
red不是所有的主要分片都可用
一个分片(shard)是一个最小级别“工作单元(worker unit)”,它只是保存了索引中所有数据的一部分。

文档元数据

节点说明
_index文档存储的地方
_type文档代表的对象的类
_id文档的唯一标识

_index

索引,类似数据库

_type

类似于”类”

空搜索

GET /_search


返回集群索引中的所有文档

一些例子:

/_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 中搜索 search types user and tweet in all indices

分词

表征化(断词)和标准化的过程叫做分词。

结构化查询 Query DSL

查询

match_all 查询

使用 match_all 可以查询到所有文档,是没有查询条件下的默认语句

{
"match_all": {}
}


match 查询

match 查询是一个标准查询,不管你需要全文本查询还是精确查询基本上都要用到它。

{
"match": {
"tweet": "About Search"
}
}


multi_match 查询

multi_match 查询允许你做 match 查询的基础上同时搜索多个字段

{

“multi_match”: {

“query”: “full text search”,

“fields”: [ “title”, “body” ]

}

}

bool 查询

bool 查询与 bool 过滤相似,用于合并多个查询子句。不同的是, bool 过滤可以直接给出是否匹配成功, 而 bool 查询要计算每一个查询子句的 _score (相关性分值)

语句含义
must查询指定文档一定要被包含。
must_not查询指定文档一定不要被包含。
should查询指定文档,有则可以为文档相关性加分。
{

“bool”: {

“must”: { “match”: { “title”: “how to make millions” }},

“must_not”: { “match”: { “tag”: “spam” }},

“should”: [

{ “match”: { “tag”: “starred” }},

{ “range”: { “date”: { “gte”: “2014-01-01” }}}

]

}

}

过滤

term 过滤

term 主要用于精确匹配哪些值,比如数字,日期,布尔值或 not_analyzed 的字符串(未经分析的文本数据类型)

{
"term": {
"age": 26
}
}


terms 过滤

terms 跟 term 有点类似,但 terms 允许指定多个匹配条件。 如果某个字段指定了多个值,那么文档需要一起去做匹配

{
"terms": {
"tag": ["search", "full_text", "nosql"]
}
}


range 过滤

range 过滤允许我们按照指定范围查找一批数据

{
"range": {
"age": {
"gte": 20,
"lt": 30
}
}
}


范围操作符包含:

符号含义
gt大于
gte大于等于
lt小于
lte小于等于
- exists 和 missing 过滤

exists 和 missing 过滤可以用于查找文档中是否包含指定字段或没有某个字段,类似于SQL语句中的 IS_NULL 条件

{
"exists": {
"field": "title"
}
}


bool 过滤

bool 过滤可以用来合并多个过滤条件查询结果的布尔逻辑,它包含一下操作符:

语句含义
must多个查询条件的完全匹配,相当于 and 。
must_not多个查询条件的相反匹配,相当于 not 。
should至少有一个查询条件匹配, 相当于 or 。
这些参数可以分别继承一个过滤条件或者一个过滤条件的数组:

{
"bool": {
"must": { "term": { "folder": "inbox" }},
"must_not": { "term": { "tag": "spam" }},
"should": [
{ "term": { "starred": true }},
{ "term": { "unread": true }}
]
}
}


查询与过滤条
c5cb
件的合并

举例:

查询语句

{
"match": {
"email": "business opportunity"
}
}


然后我们想要让这条语句加入 term 过滤,在收信箱中匹配邮件

{
"term": {
"folder": "inbox"
}
}


search API中只能包含 query 语句,所以我们需要用 filtered 来同时包含 “query” 和 “filter” 子句

{
"filtered": {
"query": { "match": { "email": "business opportunity" }},
"filter": { "term": { "folder": "inbox" }}
}
}


理解错误信息

想知道语句非法的具体错误信息,需要加上 explain 参数

例如:

GET /gb/tweet/_validate/query?explain


返回的结果中valid为false表示不合法。假设合法的话,返回true,explanations就是查询的过程了

{
"valid" : false,
"_shards" : { ... },
"explanations" : [ {
"index" : "gb",
"valid" : false,
"error" : "org.elasticsearch.index.query.QueryParsingException:[gb] No query registered for [tweet]"
} ]
}


相关性排序

字段值排序

对结果集按照时间排序,这也是最常见的情形,将最新的文档排列靠前。 我们使用 sort 参数进行排序

GET /_search{
"query" : {
"filtered" : {
"filter" : { "term" : { "user_id" : 1 }}
}
},
"sort": { "date": { "order": "desc" }}
}


有了sort后,就不需要对_score进行计算了。计算 _score 是比较消耗性能的, 而且通常主要用作排序 – 我们不是用相关性进行排序的时候,就不需要统计其相关性。

默认排序

字段值默认以顺序排序,_score默认以倒序排序

多级排序

结果集会先用第一排序字段来排序,当用用作第一字段排序的值相同的时候, 然后再用第二字段对第一排序值相同的文档进行排序,以此类推。

GET /_search{
"query" : {
"filtered" : {
"query": { "match": { "tweet": "manage text search" }},
"filter" : { "term" : { "user_id" : 2 }}
}
},
"sort": [
{ "date": { "order": "desc" }},
{ "_score": { "order": "desc" }}
]
}


正向相关和反向相关

检索词频率:出现频率越高,相关性也越高

反向文档频率:频率越高,相关性越低

字段长度准则:长度越长,相关性越低

重要: 输出 explain 结果代价是十分昂贵的,它只能用作调试工具 –千万不要用于生产环境。

扫描和滚屏

scan(扫描) 搜索类型是和 scroll(滚屏) API一起使用来从Elasticsearch里高效地取回巨大数量的结果而不需要付出深分页的代价。

scroll(滚屏)

一个滚屏搜索允许我们做一个初始阶段搜索并且持续批量从Elasticsearch里拉取结果直到没有结果剩下。这有点像传统数据

库里的cursors(游标)。

scan(扫描)

深度分页代价最高的部分是对结果的全局排序,但如果禁用排序,就能以很低的代价获得全部返回结果。为达成这个目的,可以采用 scan(扫描) 搜索模式。扫描模式让Elasticsearch不排序,只要分片里还有结果可以返回,就返回一批结果。

配置

number_of_shards:定义一个索引的主分片个数

number_of_replicas:每个主分片的复制分片个数

配置分析器

standard 分析器是用于全文字段的默认分析器,对于大部分西方语系来说是一个不错的选择。它考虑了以下几点

standard 分词器,在词层级上分割输入的文本。

standard 表征过滤器,被设计用来整理分词器触发的所有表征(但是目前什么都没做)。

lowercase 表征过滤器,将所有表征转换为小写。

stop 表征过滤器,删除所有可能会造成搜索歧义的停用词,如 a , the , and , is 。

stemmer 表征过滤器将单词转化为他们的根形态

将 & 替换成 and ,使用一个自定义的 mapping 字符过滤器

"char_filter": {
"&_to_and": {
"type": "mapping",
"mappings": [ "&=> and "]
}
}


索引别名

索引 别名 就像一个快捷方式或软连接,可以指向一个或多个索引,也可以给任何需要索引名的 API 使用。别名带给我们极大的灵活性,允许我们做到:

在一个运行的集群上无缝的从一个索引切换到另一个

给多个索引分类(例如, last_three_months )

给索引的一个子集创建 视图

在应用中使用别名而不是索引。然后你就可以在任何时候重建索引。别名的开销很小,应当广泛使用。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息