行动是治愈恐惧的良药,而犹豫、拖延将不断滋养恐惧。

【拓展篇】Elasticsearch 6.0 一个索引只允许有一个type

一,单index,单type
未来发布的elasticsearch 6.0.0版本为保持兼容,仍然会支持单index,多type结构,但是作者已不推荐这么设置。在elasticsearch 7.0.0版本必须使用单index,单type,多type结构则会完全移除。
针对这一问题,elasticsearch 作者的讨论:
https://github.com/elastic/ela ... 24317
https://www.elastic.co/guide/e ... .html
 
二,单index,多type结构弊端
人们经常会谈到index类似传统sql数据库的“database”,而type类似于"table"。现在想想,这是一个非常糟糕的比喻,而这个比喻会造成很多错误的假设。
在传统的sql数据库中,各个"table"之间是互相独立的,在一个表中的列都与另一个表相同名称的列无关。
①,而在我们elasticsearch中同一 Index 下,同名 Field 类型必须相同,即使不同的 Type;
②, 同一 Index 下,TypeA 的 Field 会占用 TypeB 的资源(互相消耗资源),会形成一种稀疏存储的情况。尤其是 doc value ,为什么这么说呢?doc value为了性能考虑会保留一部分的磁盘空间,这意味着 TypeB 可能不需要这个字段的 doc_value 而 TypeA 需要,那么 TypeB 就被白白占用了一部分没有半点用处的资源;
③,Score 评分机制是 index-wide 的,不同的type之间评分也会造成干扰。
④,索引元数据本身是放在主节点中维护的,CP 设计。意味着涉及到大量字段变更及元数据变更的操作,都会导致该 Index 被堵塞或假死。我们应该对这样的 Index 做隔离,避免影响到其他 Index 正常的增删改查。甚至当涉及到字段变更十分频繁且无法预定义 schema 的场景时,是否要使用 ES 都应该慎思熟虑了!
 
三,doc value 扩展介绍
 
参见官方文档docvalues
先看倒排索引组织结构大致如下:

倒排索引.png

 
如果我要查询包含 brown 的文档有哪些?这个就是全文检索了,也相当好办,先从词典里遍历到 brown 这个单词,然后根据倒排索引查得 Doc_1 和 Doc_2 包含这个单词。
如果我要查 Doc_1 和 Doc_2 包含的单词分别有什么?这个用倒排索引的话开销会非常大,至少是要将整张表关于 Doc_1 和 Doc_2 的列数据遍历一遍才行。这时候我们将数据换一种组织形式,将会起到非常好的效果。

image2017-9-27_11-23-5.png


Doc_1 和 Doc_2 存了什么单词,一目了然。我们把这种数据的组织方式叫做doc_value。
倒排索引的特点很明显,就是为了全文检索而生的,但是对于一些聚合查询(排序、求平均值等等)的场景来说,显然不适用。那么这样一来我们为了应对一些聚合场景就需要结构化数据来应付,这里说的结构化数据就是『列存储』,也就是上面说的doc_value。
doc_value在 ES 中有几个应用场景:
 
对某个字段排序;
某个字段聚合查询( max/min/count );
部分过滤器 ( 地理位置过滤器 );
某个字段的脚本执行。等等。
 
doc_value是顺序存储到磁盘的,因此访问是很快的。当我们所处理的集合小于所给的 JVM 堆内存,那么整个数据集合是会被加载到内存里的;如果数据集合大于所给的堆内存,那么就会分页加载到内存之中,而不会报出『OutOfMemory Error』。
 
值得一提的是,doc_value的字段使用极其频繁,因此在5.x 版本后强化成为两个字段,分别是 text 和 keyword。
text:string 类型,支持倒排索引,不支持 doc_value;
keyword:string 类型,不支持倒排索引,支持doc_value。
 
四:参考
①:ElasticSearch 内部机制浅析
 
 
 
继续阅读 »
一,单index,单type
未来发布的elasticsearch 6.0.0版本为保持兼容,仍然会支持单index,多type结构,但是作者已不推荐这么设置。在elasticsearch 7.0.0版本必须使用单index,单type,多type结构则会完全移除。
针对这一问题,elasticsearch 作者的讨论:
https://github.com/elastic/ela ... 24317
https://www.elastic.co/guide/e ... .html
 
二,单index,多type结构弊端
人们经常会谈到index类似传统sql数据库的“database”,而type类似于"table"。现在想想,这是一个非常糟糕的比喻,而这个比喻会造成很多错误的假设。
在传统的sql数据库中,各个"table"之间是互相独立的,在一个表中的列都与另一个表相同名称的列无关。
①,而在我们elasticsearch中同一 Index 下,同名 Field 类型必须相同,即使不同的 Type;
②, 同一 Index 下,TypeA 的 Field 会占用 TypeB 的资源(互相消耗资源),会形成一种稀疏存储的情况。尤其是 doc value ,为什么这么说呢?doc value为了性能考虑会保留一部分的磁盘空间,这意味着 TypeB 可能不需要这个字段的 doc_value 而 TypeA 需要,那么 TypeB 就被白白占用了一部分没有半点用处的资源;
③,Score 评分机制是 index-wide 的,不同的type之间评分也会造成干扰。
④,索引元数据本身是放在主节点中维护的,CP 设计。意味着涉及到大量字段变更及元数据变更的操作,都会导致该 Index 被堵塞或假死。我们应该对这样的 Index 做隔离,避免影响到其他 Index 正常的增删改查。甚至当涉及到字段变更十分频繁且无法预定义 schema 的场景时,是否要使用 ES 都应该慎思熟虑了!
 
三,doc value 扩展介绍
 
参见官方文档docvalues
先看倒排索引组织结构大致如下:

倒排索引.png

 
如果我要查询包含 brown 的文档有哪些?这个就是全文检索了,也相当好办,先从词典里遍历到 brown 这个单词,然后根据倒排索引查得 Doc_1 和 Doc_2 包含这个单词。
如果我要查 Doc_1 和 Doc_2 包含的单词分别有什么?这个用倒排索引的话开销会非常大,至少是要将整张表关于 Doc_1 和 Doc_2 的列数据遍历一遍才行。这时候我们将数据换一种组织形式,将会起到非常好的效果。

image2017-9-27_11-23-5.png


Doc_1 和 Doc_2 存了什么单词,一目了然。我们把这种数据的组织方式叫做doc_value。
倒排索引的特点很明显,就是为了全文检索而生的,但是对于一些聚合查询(排序、求平均值等等)的场景来说,显然不适用。那么这样一来我们为了应对一些聚合场景就需要结构化数据来应付,这里说的结构化数据就是『列存储』,也就是上面说的doc_value。
doc_value在 ES 中有几个应用场景:
 
对某个字段排序;
某个字段聚合查询( max/min/count );
部分过滤器 ( 地理位置过滤器 );
某个字段的脚本执行。等等。
 
doc_value是顺序存储到磁盘的,因此访问是很快的。当我们所处理的集合小于所给的 JVM 堆内存,那么整个数据集合是会被加载到内存里的;如果数据集合大于所给的堆内存,那么就会分页加载到内存之中,而不会报出『OutOfMemory Error』。
 
值得一提的是,doc_value的字段使用极其频繁,因此在5.x 版本后强化成为两个字段,分别是 text 和 keyword。
text:string 类型,支持倒排索引,不支持 doc_value;
keyword:string 类型,不支持倒排索引,支持doc_value。
 
四:参考
①:ElasticSearch 内部机制浅析
 
 
  收起阅读 »

【源码篇】elasticsearch 搜索模块之cross-cluster-search

一:cross-cluster-search简述:

cross cluster search(跨集群搜索)功能允许任何节点在多个集群之间充当federated client(联合客户端)。 与tribe node(部落节点)功能相比,进行cross cluster search(跨集群搜索)的节点将不会加入远程集群,而是以轻量的方式连接到远程集群,以便执行联合搜索请求。
cross cluster search(跨集群搜索)的工作原理是在集群状态中配置一个远程集群,并且仅连接到远程集群中有限数量的节点。 每个远程集群都由一个名称和一个seed nodes(种子节点)的列表引用。 这些seed nodes(种子节点)用于发现远程集群中有资格作为gateway nodes(网关节点)的节点。 集群中配置了远程集群的每个节点都连接到一个或多个gateway nodes(网关节点),并使用它们将搜索请求联合到远程集群。
注意
此功能处于测试阶段,可能会发生变化。设计和代码不如官方GA功能成熟。弹性将采取最大的努力来解决任何问题,但beta功能不受SLA官方GA功能的支持。

二:配置跨集群搜索:
远程集群可以通过cluster settings API(集群设置api)来全局性地指定(可以动态更新),或者在各个节点的elasticsearch.yml文件中单独设定
如果通过elasticsearch.yml配置远程集群,则只有具有该配置的节点才能连接到远程集群。 换句话说,联合搜索请求必须被专门发送到那些节点。 通过cluster settings API(集群设置api)设置的远程集群在集群中的每个节点上都可用。
注意
此功能已添加到Elasticsearch v5.3中,并且要求gateway eligible(具有网关资格)的节点在v5.3之后。

对于cross cluster search(跨集群搜索)节点的elasticsearch.yml配置文件只需要列出应连接到远程集群,例如:
search:
remote:
cluster_one:
seeds: 127.0.0.1:9300
cluster_two:
seeds: 127.0.0.1:9301


cluster_one和cluster_two是表示与每个集群的连接的任意集群别名。 这些名称随后用于区分本地和远程索引。

使用cluster settings API(集群设置api)将远程集群添加到集群中的所有节点的示例如下:
PUT _cluster/settings
{
"persistent": {
"search": {
"remote": {
"cluster_one": {
"seeds": [
"127.0.0.1:9300"
]
},
"cluster_two": {
"seeds": [
"127.0.0.1:9301"
]
}
}
}
}
}


通过将其种子设置为null,可以从群集设置中删除远程群集::
PUT _cluster/settings
{
"persistent": {
"search": {
"remote": {
"cluster_one": {
"seeds": null
}
}
}
}
}


cluster_one将从集群设置中删除,cluster_two保持不变。

使用跨集群搜索
要搜索远程群集cluster_one上的twitter索引,index(索引)名称必须带有以:字符分隔的群集别名的前缀:
POST /cluster_one:twitter/tweet/_search
{
"query": {
"match_all": {}
}
}


与tribe(部落)功能相反,cross cluster search(跨群集搜索)还可以搜索具有相同名称的不同群集的索引:
POST /cluster_one:twitter,twitter/tweet/_search
{
"query": {
"match_all": {}
}
}

搜索结果的消歧与在请求中消除索引歧义的方法相同。 即使索引名称相同,当结果合并时,这些索引将被视为不同的索引。 从远程索引检索的所有结果将以其远程集群名称作为前缀:
{
"took" : 89,
"timed_out" : false,
"_shards" : {
"total" : 10,
"successful" : 10,
"failed" : 0
},
"hits" : {
"total" : 2,
"max_score" : 1.0,
"hits" : [
{
"_index" : "cluster_one:twitter",
"_type" : "tweet",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"user" : "kimchy",
"postDate" : "2009-11-15T14:12:12",
"message" : "trying out Elasticsearch"
}
},
{
"_index" : "twitter",
"_type" : "tweet",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"user" : "kimchy",
"postDate" : "2009-11-15T14:12:12",
"message" : "trying out Elasticsearch"
}
}
]
}
}

跨集群搜索配置
search.remote.connections_per_cluster
要连接到每个远程集群的节点数。 默认值为3。 
search.remote.initial_connect_timeout
节点启动时与远程节点建立连接的等待时间。 默认是30秒。 
search.remote.node.attr
过滤掉远程集群中有资格作为gateway node(网关节点)的节点的节点属性。 例如,节点可以具有节点属性node.attr.gateway:true,如果search.remote.node.attr设置为gateway,只有具有此属性的节点才能将连接到。 
search.remote.connect
默认情况下,群集中的任何节点都可以充当 cross-cluster client(跨群集客户端)并连接到远程群集。 search.remote.connect设置可以设置为false(默认为true),以防止某些节点连接到远程群集。 Cross-cluster search(跨群集搜索)请求必须发送到允许充当跨群集客户端的节点。

三:官方文档
https://www.elastic.co/guide/e ... tings
继续阅读 »
一:cross-cluster-search简述:

cross cluster search(跨集群搜索)功能允许任何节点在多个集群之间充当federated client(联合客户端)。 与tribe node(部落节点)功能相比,进行cross cluster search(跨集群搜索)的节点将不会加入远程集群,而是以轻量的方式连接到远程集群,以便执行联合搜索请求。
cross cluster search(跨集群搜索)的工作原理是在集群状态中配置一个远程集群,并且仅连接到远程集群中有限数量的节点。 每个远程集群都由一个名称和一个seed nodes(种子节点)的列表引用。 这些seed nodes(种子节点)用于发现远程集群中有资格作为gateway nodes(网关节点)的节点。 集群中配置了远程集群的每个节点都连接到一个或多个gateway nodes(网关节点),并使用它们将搜索请求联合到远程集群。
注意
此功能处于测试阶段,可能会发生变化。设计和代码不如官方GA功能成熟。弹性将采取最大的努力来解决任何问题,但beta功能不受SLA官方GA功能的支持。

二:配置跨集群搜索:
远程集群可以通过cluster settings API(集群设置api)来全局性地指定(可以动态更新),或者在各个节点的elasticsearch.yml文件中单独设定
如果通过elasticsearch.yml配置远程集群,则只有具有该配置的节点才能连接到远程集群。 换句话说,联合搜索请求必须被专门发送到那些节点。 通过cluster settings API(集群设置api)设置的远程集群在集群中的每个节点上都可用。
注意
此功能已添加到Elasticsearch v5.3中,并且要求gateway eligible(具有网关资格)的节点在v5.3之后。

对于cross cluster search(跨集群搜索)节点的elasticsearch.yml配置文件只需要列出应连接到远程集群,例如:
search:
remote:
cluster_one:
seeds: 127.0.0.1:9300
cluster_two:
seeds: 127.0.0.1:9301


cluster_one和cluster_two是表示与每个集群的连接的任意集群别名。 这些名称随后用于区分本地和远程索引。

使用cluster settings API(集群设置api)将远程集群添加到集群中的所有节点的示例如下:
PUT _cluster/settings
{
"persistent": {
"search": {
"remote": {
"cluster_one": {
"seeds": [
"127.0.0.1:9300"
]
},
"cluster_two": {
"seeds": [
"127.0.0.1:9301"
]
}
}
}
}
}


通过将其种子设置为null,可以从群集设置中删除远程群集::
PUT _cluster/settings
{
"persistent": {
"search": {
"remote": {
"cluster_one": {
"seeds": null
}
}
}
}
}


cluster_one将从集群设置中删除,cluster_two保持不变。

使用跨集群搜索
要搜索远程群集cluster_one上的twitter索引,index(索引)名称必须带有以:字符分隔的群集别名的前缀:
POST /cluster_one:twitter/tweet/_search
{
"query": {
"match_all": {}
}
}


与tribe(部落)功能相反,cross cluster search(跨群集搜索)还可以搜索具有相同名称的不同群集的索引:
POST /cluster_one:twitter,twitter/tweet/_search
{
"query": {
"match_all": {}
}
}

搜索结果的消歧与在请求中消除索引歧义的方法相同。 即使索引名称相同,当结果合并时,这些索引将被视为不同的索引。 从远程索引检索的所有结果将以其远程集群名称作为前缀:
{
"took" : 89,
"timed_out" : false,
"_shards" : {
"total" : 10,
"successful" : 10,
"failed" : 0
},
"hits" : {
"total" : 2,
"max_score" : 1.0,
"hits" : [
{
"_index" : "cluster_one:twitter",
"_type" : "tweet",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"user" : "kimchy",
"postDate" : "2009-11-15T14:12:12",
"message" : "trying out Elasticsearch"
}
},
{
"_index" : "twitter",
"_type" : "tweet",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"user" : "kimchy",
"postDate" : "2009-11-15T14:12:12",
"message" : "trying out Elasticsearch"
}
}
]
}
}

跨集群搜索配置
search.remote.connections_per_cluster
要连接到每个远程集群的节点数。 默认值为3。 
search.remote.initial_connect_timeout
节点启动时与远程节点建立连接的等待时间。 默认是30秒。 
search.remote.node.attr
过滤掉远程集群中有资格作为gateway node(网关节点)的节点的节点属性。 例如,节点可以具有节点属性node.attr.gateway:true,如果search.remote.node.attr设置为gateway,只有具有此属性的节点才能将连接到。 
search.remote.connect
默认情况下,群集中的任何节点都可以充当 cross-cluster client(跨群集客户端)并连接到远程群集。 search.remote.connect设置可以设置为false(默认为true),以防止某些节点连接到远程群集。 Cross-cluster search(跨群集搜索)请求必须发送到允许充当跨群集客户端的节点。

三:官方文档
https://www.elastic.co/guide/e ... tings
收起阅读 »

【基础篇】elasticsearch之索引模板Template

一,模板简述:template大致分成setting和mappings两部分:
索引可使用预定义的模板进行创建,这个模板称作Index templates。模板设置包括settings和mappings,通过模式匹配的方式使得多个索引重用一个模板。 
1. settings主要作用于index的一些相关配置信息,如分片数、副本数,tranlog同步条件、refresh等。
 
2. mappings主要是一些说明信息,大致又分为_all、_source、prpperties这三部分:
 
     (1) _all:主要指的是AllField字段,我们可以将一个或多个都包含进来,在进行检索时无需指定字段的情况下检索多个字段。设置“_all" : {"enabled" : true}
 
     (2) _source:主要指的是SourceField字段,Source可以理解为ES除了将数据保存在索引文件中,另外还有一份源数据。_source字段在我们进行检索时相当重要,如果在{"enabled" : false}情况下默认检索只会返回ID, 你需要通过Fields字段去到索引中去取数据,效率不是很高。但是enabled设置为true时,索引会比较大,这时可以通过Compress进行压缩和inclueds、excludes来在字段级别上进行一些限制,自定义哪些字段允许存储。
 
     (3) properties:这是最重要的步骤,主要针对索引结构和字段级别上的一些设置。
3.咱们通常在elasticsearch中 post mapping信息,每重新创建索引便到设置mapping,分片,副本信息。非常繁琐。强烈建议大家通过设置template方式设置索引信息。设置索引名,通过正则匹配的方式匹配到相应的模板。ps:直接修改mapping的优先级>索引template。索引匹配了多个template,当属性等配置出现不一致的,以order的最大值为准,order默认值为0
二,创建模板:
例如:
 
{
"template": "pmall*",
"settings": {
"index.number_of_shards": 1,
"number_of_replicas": 4,
"similarity": {
"IgnoreTFSimilarity": {
"type": "IgoreTFSimilarity"
}
}
},
"mappings": {
"_default_": {
"_source": {
"enabled": false
}
},
"commodity": {
"properties": {
"sold": {
"type": "long"
},
"online_time": {
"type": "long"
},
"price": {
"type": "long"
},
"publish_time": {
"type": "long"
},
"id": {
"type": "long"
},
"catecode": {
"type": "integer"
},
"title": {
"search_analyzer": "ikSmart",
"similarity": "IgnoreTFSimilarity",
"analyzer": "ik",
"type": "text"
},
"content": {
"index": false,
"store": true,
"type": "keyword"
},
"status": {
"type": "integer"
}
}
}
}
}

 

三,删除模板:

DELETE /_template/template_1




四,查看模板:
 
GET /_template/template_1


也可以通过模糊匹配得到多个模板信息
GET /_template/temp* 


可以批量查看模板
GET /_template/template_1,template_2


验证模板是否存在:
 
HEAD _template/template_1


五:多个模板同时匹配,以order顺序倒排,order越大,优先级越高
 


PUT /_template/template_1
{
"template" : "*",
"order" : 0,
"settings" : {
"number_of_shards" : 1
},
"mappings" : {
"type1" : {
"_source" : { "enabled" : false }
}
}
}

PUT /_template/template_2
{
"template" : "te*",
"order" : 1,
"settings" : {
"number_of_shards" : 1
},
"mappings" : {
"type1" : {
"_source" : { "enabled" : true }
}
}
}


 
六,模板版本号:
 
模板可以选择添加版本号,这可以是任何整数值,以便简化外部系统的模板管理。版本字段是完全可选的,它仅用于模板的外部管理。要取消设置版本,只需替换模板即可

 
创建模板:
PUT /_template/template_1
{
"template" : "*",
"order" : 0,
"settings" : {
"number_of_shards" : 1
},
"version": 123
}


查看模板版本号:
GET /_template/template_1?filter_path=*.version



响应如下:
{
"template_1" : {
"version" : 123
}
}


七,参考:
indices-templates
继续阅读 »
一,模板简述:template大致分成setting和mappings两部分:
索引可使用预定义的模板进行创建,这个模板称作Index templates。模板设置包括settings和mappings,通过模式匹配的方式使得多个索引重用一个模板。 
1. settings主要作用于index的一些相关配置信息,如分片数、副本数,tranlog同步条件、refresh等。
 
2. mappings主要是一些说明信息,大致又分为_all、_source、prpperties这三部分:
 
     (1) _all:主要指的是AllField字段,我们可以将一个或多个都包含进来,在进行检索时无需指定字段的情况下检索多个字段。设置“_all" : {"enabled" : true}
 
     (2) _source:主要指的是SourceField字段,Source可以理解为ES除了将数据保存在索引文件中,另外还有一份源数据。_source字段在我们进行检索时相当重要,如果在{"enabled" : false}情况下默认检索只会返回ID, 你需要通过Fields字段去到索引中去取数据,效率不是很高。但是enabled设置为true时,索引会比较大,这时可以通过Compress进行压缩和inclueds、excludes来在字段级别上进行一些限制,自定义哪些字段允许存储。
 
     (3) properties:这是最重要的步骤,主要针对索引结构和字段级别上的一些设置。
3.咱们通常在elasticsearch中 post mapping信息,每重新创建索引便到设置mapping,分片,副本信息。非常繁琐。强烈建议大家通过设置template方式设置索引信息。设置索引名,通过正则匹配的方式匹配到相应的模板。ps:直接修改mapping的优先级>索引template。索引匹配了多个template,当属性等配置出现不一致的,以order的最大值为准,order默认值为0
二,创建模板:
例如:
 
{
"template": "pmall*",
"settings": {
"index.number_of_shards": 1,
"number_of_replicas": 4,
"similarity": {
"IgnoreTFSimilarity": {
"type": "IgoreTFSimilarity"
}
}
},
"mappings": {
"_default_": {
"_source": {
"enabled": false
}
},
"commodity": {
"properties": {
"sold": {
"type": "long"
},
"online_time": {
"type": "long"
},
"price": {
"type": "long"
},
"publish_time": {
"type": "long"
},
"id": {
"type": "long"
},
"catecode": {
"type": "integer"
},
"title": {
"search_analyzer": "ikSmart",
"similarity": "IgnoreTFSimilarity",
"analyzer": "ik",
"type": "text"
},
"content": {
"index": false,
"store": true,
"type": "keyword"
},
"status": {
"type": "integer"
}
}
}
}
}

 

三,删除模板:

DELETE /_template/template_1




四,查看模板:
 
GET /_template/template_1


也可以通过模糊匹配得到多个模板信息
GET /_template/temp* 


可以批量查看模板
GET /_template/template_1,template_2


验证模板是否存在:
 
HEAD _template/template_1


五:多个模板同时匹配,以order顺序倒排,order越大,优先级越高
 


PUT /_template/template_1
{
"template" : "*",
"order" : 0,
"settings" : {
"number_of_shards" : 1
},
"mappings" : {
"type1" : {
"_source" : { "enabled" : false }
}
}
}

PUT /_template/template_2
{
"template" : "te*",
"order" : 1,
"settings" : {
"number_of_shards" : 1
},
"mappings" : {
"type1" : {
"_source" : { "enabled" : true }
}
}
}


 
六,模板版本号:
 
模板可以选择添加版本号,这可以是任何整数值,以便简化外部系统的模板管理。版本字段是完全可选的,它仅用于模板的外部管理。要取消设置版本,只需替换模板即可

 
创建模板:
PUT /_template/template_1
{
"template" : "*",
"order" : 0,
"settings" : {
"number_of_shards" : 1
},
"version": 123
}


查看模板版本号:
GET /_template/template_1?filter_path=*.version



响应如下:
{
"template_1" : {
"version" : 123
}
}


七,参考:
indices-templates 收起阅读 »

【源码篇】elasticsearch 搜索模块之preference参数

一,preference简述

elasticsearch可以使用preference参数来指定分片查询的优先级,即我们可以通过该参数来控制搜索时的索引数据分片。

如不设置该参数:在所有有效的主分片以及副本间轮询。

具体可看下:OperationRouting.java类
public ShardIterator activeInitializingShardsRandomIt() {
return activeInitializingShardsIt(shuffler.nextSeed());
}
//自增,以实现shard间轮询操作
public int nextSeed() {
return seed.getAndIncrement();
}

public ShardIterator activeInitializingShardsIt(int seed) {
if (allInitializingShards.isEmpty()) {
return new PlainShardIterator(shardId, shuffler.shuffle(activeShards, seed));
}
ArrayList<ShardRouting> ordered = new ArrayList<>(activeShards.size() + allInitializingShards.size());
ordered.addAll(shuffler.shuffle(activeShards, seed));
ordered.addAll(allInitializingShards);
return new PlainShardIterator(shardId, ordered);
}
 private ShardIterator preferenceActiveShardIterator(IndexShardRoutingTable indexShard, String localNodeId, DiscoveryNodes nodes, @Nullable String preference) {
        if (preference == null || preference.isEmpty()) {
            if (awarenessAttributes.length == 0) {
                return indexShard.activeInitializingShardsRandomIt();
            } else {
                return indexShard.preferAttributesActiveInitializingShardsIt(awarenessAttributes, nodes);
            }
        }
        if (preference.charAt(0) == '_') {
            Preference preferenceType = Preference.parse(preference);
            if (preferenceType == Preference.SHARDS) {
                // starts with _shards, so execute on specific ones
                int index = preference.indexOf('|');

                String shards;
                if (index == -1) {
                    shards = preference.substring(Preference.SHARDS.type().length() + 1);
                } else {
                    shards = preference.substring(Preference.SHARDS.type().length() + 1, index);
                }
                String ids = Strings.splitStringByCommaToArray(shards);
                boolean found = false;
                for (String id : ids) {
                    if (Integer.parseInt(id) == indexShard.shardId().id()) {
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    return null;
                }
                // no more preference
                if (index == -1 || index == preference.length() - 1) {
                    if (awarenessAttributes.length == 0) {
                        return indexShard.activeInitializingShardsRandomIt();
                    } else {
                        return indexShard.preferAttributesActiveInitializingShardsIt(awarenessAttributes, nodes);
                    }
                } else {
                    // update the preference and continue
                    preference = preference.substring(index + 1);
                }
            }
            preferenceType = Preference.parse(preference);
            switch (preferenceType) {
                case PREFER_NODES:
                    final Set<String> nodesIds =
                            Arrays.stream(
                                    preference.substring(Preference.PREFER_NODES.type().length() + 1).split(",")
                            ).collect(Collectors.toSet());
                    return indexShard.preferNodeActiveInitializingShardsIt(nodesIds);
                case LOCAL:
                    return indexShard.preferNodeActiveInitializingShardsIt(Collections.singleton(localNodeId));
                case PRIMARY:
                    return indexShard.primaryActiveInitializingShardIt();
                case REPLICA:
                    return indexShard.replicaActiveInitializingShardIt();
                case PRIMARY_FIRST:
                    return indexShard.primaryFirstActiveInitializingShardsIt();
                case REPLICA_FIRST:
                    return indexShard.replicaFirstActiveInitializingShardsIt();
                case ONLY_LOCAL:
                    return indexShard.onlyNodeActiveInitializingShardsIt(localNodeId);
                case ONLY_NODES:
                    String nodeAttributes = preference.substring(Preference.ONLY_NODES.type().length() + 1);
                    return indexShard.onlyNodeSelectorActiveInitializingShardsIt(nodeAttributes.split(","), nodes);
                default:
                    throw new IllegalArgumentException("unknown preference [" + preferenceType + "]");
            }
        }
        // if not, then use it as the index
        if (awarenessAttributes.length == 0) {
            return indexShard.activeInitializingShardsIt(Murmur3HashFunction.hash(preference));
        } else {
            return indexShard.preferAttributesActiveInitializingShardsIt(awarenessAttributes, nodes, Murmur3HashFunction.hash(preference));
        }
    }

 
 
二,结果震荡问题(Bouncing Results)
 
搜索同一query,结果ES返回的顺序却不尽相同,这就是请求轮询到不同分片,而未设置排序条件,相同相关性评分情况下,是按照所在segment中​lucene id来排序的,相同数据的不同备份之间该id是不能保证一致的,故造成结果震荡问题。
如设置该参数,则有一下9种情况

`_primary`:发送到集群的相关操作请求只会在主分片上执行。
`_primary_first`:指查询会先在主分片中查询,如果主分片找不到(挂了),就会在副本中查询。 
`_replica`:发送到集群的相关操作请求只会在副本上执行。
`_replica_first`:指查询会先在副本中查询,如果副本找不到(挂了),就会在主分片中查询。
`_local`: 指查询操作会优先在本地节点有的分片中查询,没有的话再在其它节点查询。
`_prefer_nodes:abc,xyz`:在提供的节点上优先执行(在这种情况下为'abc'或'xyz')
`_shards:2,3`:限制操作到指定的分片。 (`2`和“3”)。这个偏好可以与其他偏好组合,但必须首先出现:`_shards:2,3 | _primary`
`_only_nodes:node1,node2`:指在指定id的节点里面进行查询,如果该节点只有要查询索引的部分分片,就只在这部分分片中查找,不同节点之间用“,”分隔。

custom(自定义):注意自定义的preference参数不能以下划线"_"开头。
当preference为自定义时,即该参数不为空,且开头不以“下划线”开头时,特别注意:如果以用户query作为自定义preference时,一定要处理以下划线开头的情况,这种情况下如果不属于以上8种情况,则会抛出异常。


三,参考:

https://www.elastic.co/guide/e ... .html
 
继续阅读 »
一,preference简述

elasticsearch可以使用preference参数来指定分片查询的优先级,即我们可以通过该参数来控制搜索时的索引数据分片。

如不设置该参数:在所有有效的主分片以及副本间轮询。

具体可看下:OperationRouting.java类
public ShardIterator activeInitializingShardsRandomIt() {
return activeInitializingShardsIt(shuffler.nextSeed());
}
//自增,以实现shard间轮询操作
public int nextSeed() {
return seed.getAndIncrement();
}

public ShardIterator activeInitializingShardsIt(int seed) {
if (allInitializingShards.isEmpty()) {
return new PlainShardIterator(shardId, shuffler.shuffle(activeShards, seed));
}
ArrayList<ShardRouting> ordered = new ArrayList<>(activeShards.size() + allInitializingShards.size());
ordered.addAll(shuffler.shuffle(activeShards, seed));
ordered.addAll(allInitializingShards);
return new PlainShardIterator(shardId, ordered);
}
 private ShardIterator preferenceActiveShardIterator(IndexShardRoutingTable indexShard, String localNodeId, DiscoveryNodes nodes, @Nullable String preference) {
        if (preference == null || preference.isEmpty()) {
            if (awarenessAttributes.length == 0) {
                return indexShard.activeInitializingShardsRandomIt();
            } else {
                return indexShard.preferAttributesActiveInitializingShardsIt(awarenessAttributes, nodes);
            }
        }
        if (preference.charAt(0) == '_') {
            Preference preferenceType = Preference.parse(preference);
            if (preferenceType == Preference.SHARDS) {
                // starts with _shards, so execute on specific ones
                int index = preference.indexOf('|');

                String shards;
                if (index == -1) {
                    shards = preference.substring(Preference.SHARDS.type().length() + 1);
                } else {
                    shards = preference.substring(Preference.SHARDS.type().length() + 1, index);
                }
                String ids = Strings.splitStringByCommaToArray(shards);
                boolean found = false;
                for (String id : ids) {
                    if (Integer.parseInt(id) == indexShard.shardId().id()) {
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    return null;
                }
                // no more preference
                if (index == -1 || index == preference.length() - 1) {
                    if (awarenessAttributes.length == 0) {
                        return indexShard.activeInitializingShardsRandomIt();
                    } else {
                        return indexShard.preferAttributesActiveInitializingShardsIt(awarenessAttributes, nodes);
                    }
                } else {
                    // update the preference and continue
                    preference = preference.substring(index + 1);
                }
            }
            preferenceType = Preference.parse(preference);
            switch (preferenceType) {
                case PREFER_NODES:
                    final Set<String> nodesIds =
                            Arrays.stream(
                                    preference.substring(Preference.PREFER_NODES.type().length() + 1).split(",")
                            ).collect(Collectors.toSet());
                    return indexShard.preferNodeActiveInitializingShardsIt(nodesIds);
                case LOCAL:
                    return indexShard.preferNodeActiveInitializingShardsIt(Collections.singleton(localNodeId));
                case PRIMARY:
                    return indexShard.primaryActiveInitializingShardIt();
                case REPLICA:
                    return indexShard.replicaActiveInitializingShardIt();
                case PRIMARY_FIRST:
                    return indexShard.primaryFirstActiveInitializingShardsIt();
                case REPLICA_FIRST:
                    return indexShard.replicaFirstActiveInitializingShardsIt();
                case ONLY_LOCAL:
                    return indexShard.onlyNodeActiveInitializingShardsIt(localNodeId);
                case ONLY_NODES:
                    String nodeAttributes = preference.substring(Preference.ONLY_NODES.type().length() + 1);
                    return indexShard.onlyNodeSelectorActiveInitializingShardsIt(nodeAttributes.split(","), nodes);
                default:
                    throw new IllegalArgumentException("unknown preference [" + preferenceType + "]");
            }
        }
        // if not, then use it as the index
        if (awarenessAttributes.length == 0) {
            return indexShard.activeInitializingShardsIt(Murmur3HashFunction.hash(preference));
        } else {
            return indexShard.preferAttributesActiveInitializingShardsIt(awarenessAttributes, nodes, Murmur3HashFunction.hash(preference));
        }
    }

 
 
二,结果震荡问题(Bouncing Results)
 
搜索同一query,结果ES返回的顺序却不尽相同,这就是请求轮询到不同分片,而未设置排序条件,相同相关性评分情况下,是按照所在segment中​lucene id来排序的,相同数据的不同备份之间该id是不能保证一致的,故造成结果震荡问题。
如设置该参数,则有一下9种情况

`_primary`:发送到集群的相关操作请求只会在主分片上执行。
`_primary_first`:指查询会先在主分片中查询,如果主分片找不到(挂了),就会在副本中查询。 
`_replica`:发送到集群的相关操作请求只会在副本上执行。
`_replica_first`:指查询会先在副本中查询,如果副本找不到(挂了),就会在主分片中查询。
`_local`: 指查询操作会优先在本地节点有的分片中查询,没有的话再在其它节点查询。
`_prefer_nodes:abc,xyz`:在提供的节点上优先执行(在这种情况下为'abc'或'xyz')
`_shards:2,3`:限制操作到指定的分片。 (`2`和“3”)。这个偏好可以与其他偏好组合,但必须首先出现:`_shards:2,3 | _primary`
`_only_nodes:node1,node2`:指在指定id的节点里面进行查询,如果该节点只有要查询索引的部分分片,就只在这部分分片中查找,不同节点之间用“,”分隔。

custom(自定义):注意自定义的preference参数不能以下划线"_"开头。
当preference为自定义时,即该参数不为空,且开头不以“下划线”开头时,特别注意:如果以用户query作为自定义preference时,一定要处理以下划线开头的情况,这种情况下如果不属于以上8种情况,则会抛出异常。


三,参考:

https://www.elastic.co/guide/e ... .html
  收起阅读 »

社区日报 第81期 (2017-10-26)

1.基于elasticsearch的现代银行监控api架构
part1: http://t.cn/RWaeGMB
part2: http://t.cn/RWagoth
2.父子查询?看看es的祖孙关系怎么玩
http://t.cn/RWXkPyZ
3.elasticsearch与influxdb在时序数据分析的对比
http://t.cn/RWXk46L
活动预告:Elastic 长沙交流会 
https://elasticsearch.cn/article/320

编辑:金桥
归档:https://elasticsearch.cn/article/333
订阅:https://tinyletter.com/elastic-daily
继续阅读 »
1.基于elasticsearch的现代银行监控api架构
part1: http://t.cn/RWaeGMB
part2: http://t.cn/RWagoth
2.父子查询?看看es的祖孙关系怎么玩
http://t.cn/RWXkPyZ
3.elasticsearch与influxdb在时序数据分析的对比
http://t.cn/RWXk46L
活动预告:Elastic 长沙交流会 
https://elasticsearch.cn/article/320

编辑:金桥
归档:https://elasticsearch.cn/article/333
订阅:https://tinyletter.com/elastic-daily 收起阅读 »

日报征稿

日报征稿内容要求:
  1. elastic主题相关的文章;
  2. 鼓励原创文章;
  3. 同一篇文章请勿重复投稿;


日报征稿形式要求:
  1. 简要概述投稿文章内容;
  2. 提供文章对应的链接;
  3. 中英文不限;

继续阅读 »
日报征稿内容要求:
  1. elastic主题相关的文章;
  2. 鼓励原创文章;
  3. 同一篇文章请勿重复投稿;


日报征稿形式要求:
  1. 简要概述投稿文章内容;
  2. 提供文章对应的链接;
  3. 中英文不限;

收起阅读 »

社区日报 第80期 (2017-10-25)

1. B站日志系统的前世今生
http://t.cn/ROkvWTg
2. Elasticsearch监控实战 补充昨天的
集群 http://t.cn/RO8N2iL
单节点 http://t.cn/RW5Qm8f
3. 沪江网校的日志系统实战
http://t.cn/ROriZLw
活动预告:Elastic 长沙交流会
https://elasticsearch.cn/article/320
 
编辑:江水
归档:https://elasticsearch.cn/article/330
订阅:https://tinyletter.com/elastic-daily
继续阅读 »
1. B站日志系统的前世今生
http://t.cn/ROkvWTg
2. Elasticsearch监控实战 补充昨天的
集群 http://t.cn/RO8N2iL
单节点 http://t.cn/RW5Qm8f
3. 沪江网校的日志系统实战
http://t.cn/ROriZLw
活动预告:Elastic 长沙交流会
https://elasticsearch.cn/article/320
 
编辑:江水
归档:https://elasticsearch.cn/article/330
订阅:https://tinyletter.com/elastic-daily 收起阅读 »

社区日报 第79期 (2017-10-24)

1.携程机票ElasticSearch集群运维实战。
http://t.cn/RWcy38O 
2.Elasticsearch监控那些事,指标详解!
http://t.cn/RWcyeLk 
3.微软Azure使用Elastic Stack之初体验。
http://t.cn/RWcUv6z 
活动预告:Elastic 长沙交流会
https://elasticsearch.cn/article/320 

编辑:叮咚光军
归档:https://elasticsearch.cn/article/329 
订阅:https://tinyletter.com/elastic-daily 
 
继续阅读 »
1.携程机票ElasticSearch集群运维实战。
http://t.cn/RWcy38O 
2.Elasticsearch监控那些事,指标详解!
http://t.cn/RWcyeLk 
3.微软Azure使用Elastic Stack之初体验。
http://t.cn/RWcUv6z 
活动预告:Elastic 长沙交流会
https://elasticsearch.cn/article/320 

编辑:叮咚光军
归档:https://elasticsearch.cn/article/329 
订阅:https://tinyletter.com/elastic-daily 
  收起阅读 »

社区日报 第78期 (2017-10-23)

1.每个工程师都应该知道的搜索细节。(自备梯子)
http://t.cn/RWbkpJT

2.使用Rsyslog配置logstash收集日志。
http://t.cn/RtlA8gh

3.使用ELK Stack收集jenkins构建日志。
http://t.cn/RWGhqav 

活动预告:Elastic 长沙交流会
https://elasticsearch.cn/article/320 

编辑:cyberdak
归档:https://elasticsearch.cn/article/328
订阅:https://tinyletter.com/elastic-daily
 
继续阅读 »
1.每个工程师都应该知道的搜索细节。(自备梯子)
http://t.cn/RWbkpJT

2.使用Rsyslog配置logstash收集日志。
http://t.cn/RtlA8gh

3.使用ELK Stack收集jenkins构建日志。
http://t.cn/RWGhqav 

活动预告:Elastic 长沙交流会
https://elasticsearch.cn/article/320 

编辑:cyberdak
归档:https://elasticsearch.cn/article/328
订阅:https://tinyletter.com/elastic-daily
  收起阅读 »

社区日报 第77期 (2017-10-22)

1.从Solr迁移到Elasticsearch,常用Solr查询翻译成Elasticsearch示例。
http://t.cn/RWLyKiM
2.Postgres扩展,使用Elasticsearch创建索引。
http://t.cn/RWLypo7
3.如何将数据从Splunk迁移至ELK Stack。
http://t.cn/RWLylxJ
活动预告:Elastic 长沙交流会 
https://elasticsearch.cn/article/320

编辑:至尊宝
归档:https://elasticsearch.cn/article/327
订阅:https://tinyletter.com/elastic-daily
继续阅读 »
1.从Solr迁移到Elasticsearch,常用Solr查询翻译成Elasticsearch示例。
http://t.cn/RWLyKiM
2.Postgres扩展,使用Elasticsearch创建索引。
http://t.cn/RWLypo7
3.如何将数据从Splunk迁移至ELK Stack。
http://t.cn/RWLylxJ
活动预告:Elastic 长沙交流会 
https://elasticsearch.cn/article/320

编辑:至尊宝
归档:https://elasticsearch.cn/article/327
订阅:https://tinyletter.com/elastic-daily 收起阅读 »

社区日报 第76期 (2017-10-21)

1.在macOS上利用Elastic Stack做登录日志处理的详细案例

http://t.cn/RWhNVBa

2.五种可能导致ES集群崩溃的操作,尤其针对5.0以下版本:

http://t.cn/RWhjdXR

3.适用于ES的情感分析插件

http://t.cn/RWhTFH6

活动预告:Elastic 长沙交流会

https://elasticsearch.cn/article/320




编辑:bsll

归档:https://elasticsearch.cn/article/326

订阅:https://tinyletter.com/elastic-daily
继续阅读 »
1.在macOS上利用Elastic Stack做登录日志处理的详细案例

http://t.cn/RWhNVBa

2.五种可能导致ES集群崩溃的操作,尤其针对5.0以下版本:

http://t.cn/RWhjdXR

3.适用于ES的情感分析插件

http://t.cn/RWhTFH6

活动预告:Elastic 长沙交流会

https://elasticsearch.cn/article/320




编辑:bsll

归档:https://elasticsearch.cn/article/326

订阅:https://tinyletter.com/elastic-daily 收起阅读 »

社区日报 第75期 (2017-10-20)

1、spring boot 整合 elasticsearch 5.x实现
http://t.cn/ROdYijN 
2、基于Elasticsearch搜索平台设计及踩坑教训
http://t.cn/ROdYCun 
3、深度剖析倒排索引原理
http://t.cn/RyUOW4X 

编辑:laoyang360
归档:https://elasticsearch.cn/publish/article/324
订阅:https://tinyletter.com/elastic-daily 
 
继续阅读 »
1、spring boot 整合 elasticsearch 5.x实现
http://t.cn/ROdYijN 
2、基于Elasticsearch搜索平台设计及踩坑教训
http://t.cn/ROdYCun 
3、深度剖析倒排索引原理
http://t.cn/RyUOW4X 

编辑:laoyang360
归档:https://elasticsearch.cn/publish/article/324
订阅:https://tinyletter.com/elastic-daily 
  收起阅读 »

Elasticsearch监控(理论篇)

为了KPI、为了集群的稳定性,为了集群出问题后进行回溯追踪,为了能够更早的发现集群的瓶颈,
答案就在。。。
 
 http://rickywag.com/archives/506
 

二维码201710200137.png

 
继续阅读 »
为了KPI、为了集群的稳定性,为了集群出问题后进行回溯追踪,为了能够更早的发现集群的瓶颈,
答案就在。。。
 
 http://rickywag.com/archives/506
 

二维码201710200137.png

  收起阅读 »