目录

一、逻辑设计

1. 文档

2. 类型

3. 索引

二、物理设计

1. 节点

2. 主分片与副本分片

3. 分布式索引和搜索

三、索引数据

四、搜索数据

1. 在哪里搜索

2. 回复的内容

3. 如何搜索

4. 通过ID获取文档


ES被设计为处理海量数据的高性能搜索场景。海量数据具体说至少应该是数亿文档,而高性能具体说就是从数亿文档中任意搜索需要的信息,应该在秒级返回结果。既然ES的一切都是为了性能而设计,从逻辑设计和物理设计两个角度考察ES的数据组织,对于理解ES的工作原理会有帮助。

  • 逻辑设计:用于索引和搜索的基本单位是文档,可以将其认为是关系数据库里的一行记录。文档以类型分组,类型包含若干文档,类似表中包含若干行。最终,一个或多个类型存储于同一索引中,索引是更大的容器,类似于SQL世界中的数据库。ES6中类型的概念已经过时,并且将在7中彻底弃用。因此在我的环境中,ES索引和文档就对应数据库的表和记录。
  • 物理设计:物理设计的配置方式决定了集群的性能、可扩展性和可用性。ES将每个索引划分为片,缺省为5片,每份分片可以在集群中不同的服务器间迁移。通常,应用程序无须关心这些,因为无论ES是单台还是多台服务器,应用和ES的交互基本保持不变。

图1展示了这两个方面:

图1 ES逻辑设计与物理设计

一、逻辑设计

图2所示为一个ES索引的逻辑结构。

图2 ES数据的逻辑设计

在ES6中,一个索引中只能有一个类型,缺省名为_doc。索引-类型-文档ID的组合唯一确定了一篇文档,文档ID可以是任意字符串。当进行搜索的时候,可以查找特定的索引中的文档,也可以跨多个索引进行搜索,类似于单表或多表查询。但和关系数据库不同的是,ES并不支持关系数据库中表之间的join,或者嵌套子查询。

1. 文档

ES是面向文档的,索引和搜索的最小单位是文档。ES中文档有几个重要的属性。

  • 它是自包含的。一篇文档中同时包含字段和字段的取值。关系库的表结构是元数据,与真正数据的存储和管理方式是不同的。但ES中文档数据本身就包含了字段名和字段值。
  • 它可以是层次的。文档中可以包含其它文档。一个字段可以是简单的,如一个字符串,也可以包含其它字段和取值。
  • 它是无模式的。文档不依赖于预先定义的模式,不同文档的字段可以不同。

一篇文档通常是数据的JSON表示。和ES沟通最为广泛的方式是HTTP协议上的JSON。下面是个简单文档的例子:

{"name": "Elasticsearch Denver","organizer": "Lee","location": "Denver, Colorado, USA"
}

下面是一个层次型文档的例子:

{"name": "Elasticsearch Denver","organizer": "Lee","location": {"name": "Denver, Colorado, USA","geolocation": "39.7392, -104.9847"}
}

一个简单的文档也可以包含一组数值,例如:

{"name": "Elasticsearch Denver","organizer": "Lee","members": ["Lee", "Mike"]
}

ES中的文档是无模式的,也就是说并非所有的文档都需要拥有相同的字段,它们不是受限于同一个模式。尽管可以随意添加和忽略字段,但是每个字段的类型很重要。ES保存字段和类型之间的映射以及其它设置,类似于表结构。

2. 类型

ES6中类型的概念已经过时。在ES6之前的版本中,类型是文档的容器,类似于表格是行的容器。每个类型中字段的定义称为映射(mapping),每种字段通过不同的方式进行处理。

既然ES是无模式的,为什么每个文档属于一种类型,而且每个类型包含一个看上去很像模式的映射呢?我们说“无模式”是因为文档不受模式的限制。它们并不需要拥有映射中所定义的所有字段,也能提出新的字段。这是如何运作的?首先,映射包含某个类型中当前索引的所有文档的所有字段。但不是所有的文档必须要有所有的字段。同样,如果一篇新索引的文档拥有一个映射中尚不存在的字段,ES会自动地将新字段加入映射。为了添加这个字段,ES需要确定它是什么类型,于是ES会根据字段值进行猜测。例如,如果值是7,ES会假设字段是长整型。

这种对新字段的自动检测也有缺点,因为ES可能猜得不对。例如,在索引了值7之后,可能想再索引hello world,这时由于它是text而不是long,索引就会失败,对于线上环境,最安全的方式是在索引数据之前,就定义好所需的映射。从这个角度看很像数据库,在加入数据前先建表。所以在实际应用中,常见的使用方式还是先仔细定义好映射,再装载数据。

映射只是将文档进行逻辑划分。从物理角度看,文档写入磁盘时不考虑它们所属的类型。

3. 索引

索引是文档的容器,一个ES索引非常像关系数据库中的表,是独立的大量文档的集合。每个索引存储在磁盘上的同组文件中;索引存储了所有字段的映射和数据,还有一些设置。例如,每个索引有一个称为refresh_interval的设置,定义了新文档对于搜索可见的时间间隔。从性能的角度看,刷新操作的代价是非常昂贵的。ES的索引数据是写入到磁盘上的。但这个过程是分阶段实现的,因为IO的操作比较费时。

  1. 先写到内存中,此时不可搜索。
  2. 默认经过 1s 之后会被写入 lucene 的底层文件 segment 中 ,此时可以搜索到。
  3. refresh 之后才会写入磁盘。

ES被称为准实时的,指的就是这种刷新过程。

二、物理设计

默认情况下,每个索引由5个分片组成,而每个分片又有一个副本,一共10个分片。如图3所示。

图3 一个有3个节点的集群,索引被划分为5个主分片,每个主分片有一个副本分片

技术上而言,一个分片是一个的文件,Lucene用这些文件存储索引数据。分片也是ES将数据从一个节点迁移到另一个节点的最小单位。

1. 节点

一个节点是一个ES实例,多个节点可以加入同一集群。在多节点的集群上,同样的数据可以在多台服务器上传播。如果每分片至少有一个副本,那么任何一个节点都可以宕机,而ES依然可以进行服务,返回所有数据。对于应用程序,集群中有1个还是多个节点是透明的。默认情况下,可以连接集群中的任一节点并访问完整的数据集。

默认情况下,当索引一篇文档时,系统首先根据文档ID的散列值选择一个主分片,并将文档发送到该主分片。这个主分片可能位于另一个节点,如图4中节点2上的主分片,不过对于应用程序这一点是透明的。

图4 文档被索引到随机的主分片和它们的副本分片。搜索在完整的分片集合上运行,无论它们的状态是主分片还是副本分片。

然后文档被发送到该主分片的所有副本分片进行索引(如图4的左边)。这使得副本分片和主分片之间保持数据的同步。数据同步使得副本分片可以服务于搜索请求,并在原主分片无法访问时自动升级为主分片。

当搜索一个索引时,ES需要在该索引的完整集合中进行查找(见图4的右边)。这些分片可以是分片,也可以是副本分片。ES在索引的主分片和副本分片中进行搜索请求的负载均衡,使得副本分片对于搜索性能和容错都有所帮助。

2. 主分片与副本分片

分片是ES最小的处理单元,一个分片是一个Lucene的索引:一个包含倒排索引的文件目录。如图5所示,get-together索引的首个主分片可能包含何种信息。该分片称为get-together0,它是一个Lucene索引、一个倒排索引。它默认存储原始文档的内容,再加上一些额外的信息,如词条字典和词频。

图5 Lucene索引中的词条字典和词频

词条字典将每个词条和包含该词条的文档映射起来。搜索的时候,ES没必要为了某个词条扫描所有文档,而是根据这个字典快速识别匹配的文档。

词频使得ES可以快速地获取谋篇文档中某个词条出现的次数。这对于计算结果的相关性得分非常重要。更高得分的文档出现在结果列表的更前面。默认的排序算法是TF-IDF。

可以在任何时候改变每个分片的副本分片的数量,因为副本分片总是可以被创建和移除。但主分片的数量必须在创建索引之前确定,索引创建后主分片的数量不能修改。过少的分片将限制可扩展性,但过多的分片影响性能。默认设置的5份是个不错的开始。

3. 分布式索引和搜索

索引的过程如图6所示。接受索引请求的ES节点首先选择文档索引到哪个分片。默认的,文档在分片中均匀分布:对于每篇文档,分片是通过其ID字符串的散列决定的。每个分片拥有相同的散列范围,接收新文档的机会均等。一旦目标分片确定,接受请求的节点将文档转发到该分片所在节点。随后,索引操作在所有目标分片的副本分片中进行。在所有可用副本分片完成文档的索引后,索引命令就会返回成功。

图6 索引操作被转发到相应的分片,然后转发到它的副本分片。

在搜索的时候,接受请求的节点将请求转发到一组包含所有数据的分片。ES使用round-robin的轮询机制选择可用的分片(主分片或副本分片),并将搜索请求转发过去,其假设集群中的所有节点是同样快的。如图7所示,ES然后从这些分片收集结果,将其聚集到单一的结果返回给应用程序。

图7 转发搜索请求到包含完整数据集合的主分片/副本分片,然后聚集结果并将其发送回客户端。

三、索引数据

可以使用curl的PUT方法索引一个文档,如:

curl -XPUT '172.16.1.127:9200/get-together/_doc/1?pretty' -H 'Content-Type: application/json' -d '
{"name": "Elasticsearch Denver","organizer": "Lee"
}'

这句DSL语句的功能是向索引get-together中新增一个ID为1的文档,类似于SQL的insert命令:

insert into get-together (id, name, organizer) values (1, 'Elasticsearch Denver', 'Lee');

输出如下:

{"_index" : "get-together","_type" : "_doc","_id" : "1","_version" : 1,"result" : "created","_shards" : {"total" : 2,"successful" : 2,"failed" : 0},"_seq_no" : 0,"_primary_term" : 1
}

回复中包含索引、类型和文档ID。如果索引和类型不存在,则会自动创建。文档ID也可以由ES自动生成。这里还获得了文档的版本,它从1开始并随着每次的更新而增加。ES使用这个版本号实现并发更新时的乐观锁功能,防止类似关系数据库中的第二类更新丢失问题。

这个curl命令之所以可以奏效,是因为ES自动创建了get-together和_doc类型,并为_doc类型创建了一个新的映射。映射包含字符串字段的定义。默认情况下ES处理所有这些,无需任何事先配置,就可以开始索引。

使用下面的命令查询索引的映射:

curl '172.16.1.127:9200/get-together/_mapping?pretty'

返回如下。可以看到,ES自动将name和organizer字段识别为text类型:

{"get-together" : {"mappings" : {"_doc" : {"properties" : {"name" : {"type" : "text","fields" : {"keyword" : {"type" : "keyword","ignore_above" : 256}}},"organizer" : {"type" : "text","fields" : {"keyword" : {"type" : "keyword","ignore_above" : 256}}}}}}}
}

映射类型包含与文档相关的字段或属性列表。ES缺省将字符串数据映射为text和keyword。因此,可以对name和organizer字段执行全文搜索,同时使用name.keyword或organizer.keyword执行原文匹配和聚合。

可以手动创建索引:

curl -XPUT '172.16.1.127:9200/new-index?pretty'

类似于创建一个名为new-index的表,但这里只指定了索引名称,返回如下:

{"acknowledged" : true,"shards_acknowledged" : true,"index" : "new-index"
}

如果只想建立字符串类型的倒排索引搜索字段,而不映射keyword字段,只需要在创建索引时显式指定mapping:

curl -XPUT '172.16.1.127:9200/myindex?pretty' -H 'Content-Type: application/json' -d '
{"mappings": {"_doc": {"properties": {"name": {"type": "text"},"organizer": {"type": "text"}}}}
}'curl '172.16.1.127:9200/myindex/_mapping?pretty'
{"myindex" : {"mappings" : {"_doc" : {"properties" : {"name" : {"type" : "text"},"organizer" : {"type" : "text"}}}}}
}

四、搜索数据

下面的命令搜索get-together索引中包含“elasticsearch”关键词的文档,但只获取最相关文档的name和location_event.name字段。功能类似于SQL语句:

select name, location_event from get-together where column1 like '%elasticsearch%' or column2 like '%elasticsearch%'...or columnn like '%elasticsearch%'order by _scorelimit 1;

下面两种写法是等价的,但后者的可读性更好。这个例子中的搜索条件没有指定任何字段,意为在所有字段中搜索。

curl "172.16.1.127:9200/get-together/_search?\
q=elasticsearch\
&_source=name,location_event.name\
&size=1\
&pretty"curl "172.16.1.127:9200/get-together/_search?pretty" -H 'Content-Type: application/json' -d'
{"_source": ["name","location_event.name"],"query": {"query_string": {"query": "elasticsearch"}},"size": 1
}'

结果返回:

{"took" : 6,"timed_out" : false,"_shards" : {"total" : 2,"successful" : 2,"skipped" : 0,"failed" : 0},"hits" : {"total" : 10,"max_score" : 1.4880564,"hits" : [{"_index" : "get-together","_type" : "_doc","_id" : "2","_score" : 1.4880564,"_source" : {"name" : "Elasticsearch Denver"}}]}
}

1. 在哪里搜索

可以指定ES在特定索引中进行查询,但也可以在同一个索引的多个字段中搜索、在多个索引或在所有索引中搜索。

# 在多个索引中搜索
curl "172.16.1.127:9200/get-together,myindex/_search?q=elasticsearch&pretty"# ignore_unavailable=true会忽略不存在的索引,而不是返回错误
curl "172.16.1.127:9200/get-together,myindex/_search?q=name:elasticsearch&pretty&ignore_unavailable=true"# 为了在所有索引中搜索,省略索引名称
curl "172.16.1.127:9200/_search?q=name:elasticsearch&pretty"

这种关于“在哪里搜索”的灵活性,允许在多个索引中组织数据。例如,日志事件经常以基于时间的索引组织,如“logs-20190101”、“logs-20190102”等。可以只搜索最新的索引,也可以在多个索引或全量数据里搜索。

2. 回复的内容

(1)时间
        除了和搜索条件匹配的文档,搜索回复还包含其它有价值的信息,用于检验搜索的性能或结果的相关性。ES的JSON应答包含了时间、分片、命中统计数据、文档等。

took字段表示ES处理请求所花的时间,单位是毫秒。timed_out字段表示搜索请求是否超时,默认情况下,搜索永远不会超时,但是可以通过timeout参数设定超时时间。例如下面的搜索在3秒后超时:

curl "172.16.1.127:9200/get-together/_search?q=elasticsearch&pretty&timeout=3s"

如果搜索超时,timed_out的值就是true,而且只能获得超时前所获得的结果。
  
(2)分片
        回复的下一部分是搜索相关的分片信息:

"_shards" : {"total" : 2,"successful" : 2,"skipped" : 0,"failed" : 0
}

get-together索引有两个分片,所有分片都有返回,所以成功(successful)的值是2,而失败(failed)的值是0。图8展示了一个拥有3个节点的集群,每个节点只有一份分片且没有副本分片。如果某个节点宕机了,就会丢失某些数据。在这种情况下,ES提供正常分片中的结果,并在failed字段中报告不可搜索的分片数量。

图8 仍然可用的分片将返回部分结果

(3)命中统计数据
        回复的最后一项组成元素是hits,这项相当长因为它包含了匹配文档的数组。数组之前包含了几项统计数据:

"total" : 10,
"max_score" : 1.4880564

total表示匹配文档的总数,max_score是这些匹配文档的最高得分。文档得分,是该文档和给定搜索条件的相关性衡量,得分默认是通过TF-IDF算法进行计算的。

匹配文档的总数和回复中的文档数量可能并不相同。ES默认限制结果数为10,可使用size参数修改返回的结果数量。查看total字段的值,可以获取匹配搜索条件的精确文档数量。

(4)结果文档

"hits" : [{"_index" : "get-together","_type" : "_doc","_id" : "2","_score" : 1.4880564,"_source" : {"name" : "Elasticsearch Denver"}}
]

结果中包括每个匹配文档所属的索引、类型、它的ID、得分,以及搜索查询中所指定的字段的值。查询中使用了_source=name,location_event.name。如果结果中某个指定字段的值为空,缺省没有该字段的定义,就像结果中没有location_event.name字段。这点和数据库不同,数据库是有schema的,字段值和表定义分开处理,即使某字段没有值,结果中该字段也会有个NULL值。如果不指定需要哪些字段,会返回“_source”中的所有字段。_source是一个特殊的字段,ES默认在其中存储原始的JSON文档。

3. 如何搜索

(1)设置查询的字符串选项
        query_string提供了除字符串之外的更多选项。例如,如果搜索“Elasticsearch san Francisco”,ES默认查询所有字段。如果想在名称和标题中查询,需要指定:

"fields": ["name", "title"]

ES默认返回匹配了任一指定关键词的文档(默认的操作符是OR)。如果希望匹配所有的关键词,需要指定:

"default_operator": "AND"

修改后的查询如下:

curl "172.16.1.127:9200/get-together/_search?pretty" -H 'Content-Type: application/json' -d'
{"query": {"query_string": {"query": "elasticsearch","fields": ["name", "title"],"default_operator": "AND"}}
}'

查询字符串是指定搜索条件的强大工具。ES分析字符串并理解所查找的词条和其它选项,如字段和操作符,然后执行查询。这项功能是从Lucene继承而来。

(2)选择合适的查询类型
        除query_string外,ES还有很多其它类型的查询。例如,如果在name字段中只查找“elasticsearch”一个词,term查询更直接:

curl "172.16.1.127:9200/get-together/_search?pretty" -H 'Content-Type: application/json' -d'
{"query": {"term": {"name": "elasticsearch"}}
}'

(3)使用过滤器
        如果不需要通过结果得分返回结果,可以使用过滤器查询替代。过滤器查询只关心一条结果是否匹配搜索条件,因此过滤器查询更快,而且更容易缓存。例如:

curl "172.16.1.127:9200/get-together/_search?pretty" -H 'Content-Type: application/json' -d'
{"query": {"bool": {"filter": {"term": {"name": "elasticsearch"}}}}
}'

返回的结果和同样词条的查询相同,但结果没有根据得分排序,因为所有的结果得分都是0。

(4)应用聚合
        除了查询和过滤,还可以通过聚合进行各种统计。例如实现SQL的简单聚合:

select count(*), organizer from get-together group by organizer;

ES查询命令如下:

curl 172.16.1.127:9200/get-together/_doc/_search?pretty -H 'Content-Type: application/json' -d '
{"aggregations": {"organizers": {"terms": {"field": "organizer"}}}
}'

当在get-together索引上执行此聚合查询时,报以下错误:
"Fielddata is disabled on text fields by default. Set fielddata=true on [organizer] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory. Alternatively use a keyword field instead."

ES聚合使用一个叫Doc Values的数据结构。Doc Values使聚合更快、更高效且内存友好。Doc Values的存在是因为倒排索引只对某些操作是高效的。倒排索引的优势在于查找包含某个条目的文档,而反过来确定哪些条目在单个文档里并不高效。

Doc Values结构类似如下:
Doc      Terms
-----------------------------------------------------------------
Doc_1 | brown, dog, fox, jumped, lazy, over, quick, the
Doc_2 | brown, dogs, foxes, in, lazy, leap, over, quick, summer
Doc_3 | dog, dogs, fox, jumped, over, quick, the
     
        Doc values在索引时生成,伴随倒排索引创建。像倒排索引一样基于per-segment,且是不可变,被序列化存储到磁盘。通过序列化持久化数据结构到磁盘,可以用操作系统的文件缓存来代替JVM heap。但是当工作空间需要的内存很大时,Doc Values会被置换出内存,这样会导致访问速度降低,但是如果放在JVM heap,将直接导致内存溢出错误。

Doc Values默认对除了分词的所有字段起作用。因为分词字段产生太多tokens且Doc Values对其并不是很有效。Doc Values默认开启,如果不执行基于一个确定的子段聚合、排序或执行脚本(Script ),可以选择关闭Doc Values,这可以节省磁盘空间,提高索引数据的速度。

text字段不支持doc_values,text使用fielddata,一种在查询时期生成在缓存里的数据结构。当字段在首次sort、aggregations或in a script时创建,读取磁盘上所有segment的倒排索引,反转 term<->doc 的关系,加载到jvm heap,它将在segment的整个生命周期内一直存在。fielddata很耗内存,默认禁用fielddata。text字段是先分词再索引的,因此,应该使用不分词的keyword用来聚合。

organizer字段的mapping如下:

"organizer" : {"type" : "text"
}

正如错误提示中所指出的,要解决这个问题,可选择两种方式:一是设置fielddata=true,二是增加keyword字段。第一种方法可以即时生效,第二种方法需要重新索引数据才能生效。所以建议在创建index时,仔细定义mapping,以免以后修改结构产生问题。

第一种方式:

# 设置fielddata=true
curl -XPOST "172.16.1.127:9200/get-together/_mapping/_doc?pretty" -H 'Content-Type: application/json' -d'
{"properties": {"organizer": {"type": "text","fielddata": "true"}}
}'# 执行聚合查询
curl 172.16.1.127:9200/get-together/_doc/_search?pretty -H 'Content-Type: application/json' -d '
{"aggregations": {"organizers": {"terms": {"field": "organizer"}}}
}'

第二种方式:

# 修改organizer字段的映射
curl -XPOST "172.16.1.127:9200/get-together/_mapping/_doc?pretty" -H 'Content-Type: application/json' -d'
{"properties": {"organizer": {"type": "text","fields": {"keyword": {"type": "keyword","ignore_above": 256}}}}
}'# 重新索引数据# 在organizer.keyword字段上执行聚合
curl 172.16.1.127:9200/get-together/_doc/_search?pretty -H 'Content-Type: application/json' -d '
{"aggregations": {"organizers": {"terms": {"field": "organizer.keyword"}}}
}'

返回的聚合结果如下:

"aggregations" : {"organizers" : {"doc_count_error_upper_bound" : 0,"sum_other_doc_count" : 0,"buckets" : [{"key" : "Lee","doc_count" : 2},{"key" : "Andy","doc_count" : 1},{"key" : "Daniel","doc_count" : 1},{"key" : "Mik","doc_count" : 1},{"key" : "Tyler","doc_count" : 1}]}}

关于Doc Values和FieldData的更多说明,参见“Es官方文档整理-3.Doc Values和FieldData”。

4. 通过ID获取文档

为了获取一个具体的文档,必须要知道它所属的索引、类型和ID。然后就可以发送HTTP GET请求到这篇文档的URI:

curl '172.16.1.127:9200/get-together/_doc/1?pretty'

回复包括所指定的索引、类型和ID。如果文档存在,found字段的值是true,此外还有其版本和源。如果文档不存在,found字段的值是false:

curl '172.16.1.127:9200/get-together/_doc/doesnt-exist?pretty'

返回:

{"_index" : "get-together","_type" : "_doc","_id" : "doesnt-exist","found" : false
}

通过ID获得文档要比搜索更快,所消耗的资源成本也更低。这也是实时完成的:只要索引操作完成了,新的文档就可以通过GET API获取。相比之下,搜索是近实时的,因为它们需要等待默认情况下每秒进行一次的刷新操作。这个思想和DB也类似,通过主键查询通常是查询数据最快的途径。

触类旁通Elasticsearch:原理相关推荐

  1. 图解elasticsearch原理转载自

    转载自  图解elasticsearch原理 版本 elasticsearch版本: elasticsearch-2.x 内容 图解ElasticSearch 云上的集群 集群里的盒子 云里面的每个白 ...

  2. Elasticsearch 原理(六):深入了解Elasticsearch存储

    本文我们深入了解关于Elasticsearch存储,如我们写入Elasticsearch的数据是如何在节点上存储的. Elasticsearch的路径 Elasticsearch主要有以下路径: pa ...

  3. 触类旁通Elasticsearch:扩展

    目录 一.添加节点 二.节点发现 1. 广播 2. 单播 3. 选举主节点 4. 错误识别 三.删除节点 1. 丢失节点 2. 停用节点 四.升级节点 五.使用_cat API 六.扩展策略 1. 过 ...

  4. ElasticSearch原理应用以及京东搜索案例

    ElasticSearch原理,应用以及仿京东搜索功能 1.ElasticSearch简介 ElasticSearch:智能搜索,分布式的搜索引擎 是ELK的一个组成,是一个产品,而且是非常完善的产品 ...

  5. 由浅及深学习 elasticSearch 原理

    第三节 ElasticSearch原理 3.1 解析es的分布式架构 3.1.1 分布式架构的透明隐藏特性 ElasticSearch是一个分布式系统,隐藏了复杂的处理机制 分片机制:我们不用关心数据 ...

  6. elasticsearch原理_ElasticSearch读写底层原理及性能调优

    ES写入/查询底层原理 1. Elasticsearch写入数据流程 客户端随机选择一个ES集群中的节点,发送POST/PUT请求,被选择的节点为协调节点(coordinating node) 协调节 ...

  7. elasticsearch原理学习笔记

    https://mp.weixin.qq.com/s/dn1n2FGwG9BNQuJUMVmo7w 感谢,透彻的讲解 整理笔记 请说出 唐诗中 包含 前  的诗句 ...... 其实你都会,只是想不起 ...

  8. 终于有人把 Elasticsearch 原理讲透了

    上个世纪末,我在广州做 PHP 程序员,那会儿程序员的门槛真低啊.我的上司是技术经理,非常照顾我.有个客户是开律所的,过来提了一个私活的需求,要做个法律查询的网站. 上司让我赚点外块,说干就干,整个 ...

  9. 图解 Elasticsearch 原理

    摘要 先自上而下,后自底向上的介绍ElasticSearch的底层工作原理,试图回答以下问题: 为什么我的搜索 *foo-bar* 无法匹配 *foo-bar* ? 为什么增加更多的文件会压缩索引(I ...

最新文章

  1. python3中tkinter button属性_Python3 tkinter基础 Button bg 按钮的背景颜色
  2. 3.1.1蛮力法之选择排序
  3. 160个Crackme024之Opcode加密
  4. MacBookPro 关机花屏解决
  5. Gym 100917J---Judgement(01背包+bitset)
  6. 隧道凿岩机器人_隧道凿岩机器人的研制
  7. qt, connect参数,Qt::DirectConnection,Qt::QueuedConnection
  8. Python爬取王者荣耀皮肤
  9. jasper s java jacal_Jasper's Java Jacal
  10. 计算机操作系统的功能有哪些,操作系统的基本功能是什么
  11. 普通用户sudo echo权限依旧写入不了文件
  12. 总结一下Android中主题(Theme)的正确玩法
  13. ubuntu桌面被删除或home文件跑到桌面问题
  14. #Tensorflow Process finished with exit code 3#
  15. python足球数据可视化_欧洲足球,5大联赛!Python爬虫数据可视化带你解析经典赛事...
  16. 那些让人“上瘾”的产品,是如何铺设流量陷阱的?
  17. 浙江大学电子信息计算机,浙江大学城市学院计算机与计算科学学院 党政办 计算学院新增12名浙江大学电子信息专业硕士研究生导师...
  18. git 将暂存区文件提交_git基础命令之提交文件
  19. Codeforces Round #826 (Div. 3)(A~D)
  20. phpcms 更换新域名更新栏目url和内容页url无法更新解决方法

热门文章

  1. iptables防火墙与SNAT和DNAT
  2. 从Telnet到TCP,从HTTP2.0到QUIC
  3. 2023 弹幕播放器解析源码
  4. 【HZHE002】黄子涵学习Echarts
  5. 塞尔达风之杖技术分析-角色渲染和面部表情
  6. KUKA机器人之系统镜像
  7. 《一人之下》佳句欣赏
  8. linux管道命令的简单操作
  9. STM32 脉宽调制 (PWM):控制直流风扇的速度
  10. 好的软件架构设计(转)