什么是ElasticSearch
Elasticsearch 是一个分布式、RESTful 风格的搜索和数据分析引擎,适用于包括文本、数字、地理空间、结构化和非结构化数据等在内的所有类型的数据。Elasticsearch 在 Apache Lucene 的基础上开发而成,由 Elasticsearch N.V.(即现在的 Elastic)于 2010 年首次发布。Elasticsearch 以其简单的 REST 风格 API、分布式特性、速度和可扩展性而闻名,是 Elastic Stack 的核心组件;Elastic Stack 是一套适用于数据采集、扩充、存储、分析和可视化的免费开源工具。人们通常将 Elastic Stack 称为 ELK Stack(代指 Elasticsearch、Logstash 和 Kibana),目前 Elastic Stack 包括一系列丰富的轻量型数据采集代理,这些代理统称为 Beats,可用来向 Elasticsearch 发送数据。
全文检索是我们在实际项目开发中最常见的需求了,而ElasticSearch是目前全文检索引擎的首选,它可以快速的存储,搜索和分析海量的数据,维基百科,GitHub,Stack Overflow都采用了ElasticSearch。
官方网站:https://www.elastic.co/cn/elasticsearch/
中文社区:https://elasticsearch.cn/explore/
Elasticsearch是java开发的,在7.8版本以上,需要使用jdk1.8以上版本。
官网访问地址:https://www.elastic.co/cn/downloads/elasticsearch
Elasticsearch是面向文档型数据库,一条数据在这里就是一个文档。为了方便大家理解,我们将Elasticsearch里存储文档数据与关系型数据库mysql存储数据的概念进行类比
ES里的Index可以看做一个库,而type相当于表,Documents相当于行。
这里type的概念逐渐被弱化,Elasticsearch 6.x中,一个index下只能包含一个type,Elasticsearch 7.x中,type的概念已经被删除了。
Elasticsearch 的用途是什么?
Elasticsearch 在速度和可扩展性方面都表现出色,而且还能够索引多种类型的内容,这意味着其可用于多种用例:
应用程序搜索 搜索的数据对象是大量的非结构化的文本数据。
网站搜索 文件记录达到数十万或数百万个甚至更多。
企业搜索 需求非常灵活的全文搜索查询。
日志处理和分析
基础设施指标和容器监测
应用程序性能监测
地理空间数据分析和可视化
安全分析
业务分析
ElasticSearch基本概念
ES存储结构 | Mysql存储结构 |
---|---|
Index(索引) | 表 |
文档 | 行,一行数据 |
Field(字段) | 表字段 |
mapping(映射) | 表结构定义 |
类型
类型是用来定义数据结构的
在每一个index下面,可以有一个或者多个type,好比数据库里面的一张表。
相当于表结构的描述,描述每个字段的类型。
文档
文档就是最终的数据了,可以认为一个文档就是一条记录。
是ES里面最小的数据单元,就好比表里面的一条数据
字段
好比关系型数据库中列的概念,一个document有一个或者多个field组成。
Node节点
就是集群中的一台服务器
shard:分片
一台服务器,无法存储大量的数据,ES把一个index里面的数据,分为多个shard,分布式的存储在各个服务器上面。
replica:副本
一个分布式的集群,难免会有一台或者多台服务器宕机,如果我们没有副本这个概念。就会造成我们的shard发生故障,无法提供正常服务。
我们为了保证数据的安全,我们引入了replica的概念,跟hdfs里面的概念是一个意思。可以保证我们数据的安全。
在ES集群中,我们一模一样的数据有多份,能正常提供查询和插入的分片我们叫做 primary shard,其余的我们就管他们叫做 replica shard(备份的分片)
当我们去查询数据的时候,我们数据是有备份的,它会同时发出命令让我们有数据的机器去查询结果,最后谁的查询结果快,我们就要谁的数据(这个不需要我们去控制,它内部就自己控制了)
在默认情况下,我们创建一个库的时候,默认会帮我们创建5个主分片(primary shrad)和5个副分片(replica shard),所以说正常情况下是有10个分片的。
同一个节点上面,副本和主分片是一定不会在一台机器上面的,就是拥有相同数据的分片,是不会在同一个节点上面的。
所以当你有一个节点的时候,这个分片是不会把副本存在这仅有的一个节点上的,当你新加入了一台节点,ES会自动的给你在新机器上创建一个之前分片的副本。
倒排索引
Elasticsearch是通过Lucene的倒排索引技术实现比关系型数据库更快的过滤。特别是它对多条件的过滤支持非常好.
倒排索引是搜索引擎的核心。搜索引擎的主要目标是在查找发生搜索条件的文档时提供快速搜索。ES中的倒排索引其实就是 lucene 的倒排索引,区别于传统的正向索引,倒排索引会再存储数据时将关键词和数据进行关联,保存到倒排表中,然后查询时,将查询内容进行分词后在倒排表中进行查询,最后匹配数据即可。
ElasticSearch相关安装
Elasticsearch安装
Elasticsearch介绍和安装
elastic产品各个版本下载地址
ElasticSearch集群
ELK日志监控系统搭建
ElasticSearch配置文件详解
- 集群名称,默认为elasticsearch #配置es的集群名称,同一个集群中的多个节点使用相同的标识
#如果在同一网段下有多个集群,就可以用这个属性来区分不同的集群。
cluster.name: elasticsearch
2. 节点名称,es启动时会自动创建节点名称,但你也可进行配置:
node.name: “aaa”
3. 是否作为主节点,每个节点都可以被配置成为主节点,默认值为true:
node.master: true
4. 是否存储数据,即存储索引片段,默认值为true:
node.data: true
master和data同时配置会产生一些奇异的效果:
1) 当master为false,而data为true时,会对该节点产生严重负荷;
2) 当master为true,而data为false时,该节点作为一个协调者;
3) 当master为false,data也为false时,该节点就变成了一个负载均衡器。
你可以通过连接http://localhost:9200/_cluster/health或者http://localhost:9200/_cluster/nodes,或者使用插件http://github.com/lukas-vlcek/bigdesk或http://mobz.github.com/elasticsearch-head来查看集群状态。
5. 每个节点都可以定义一些与之关联的通用属性,用于后期集群进行碎片分配时的过滤:
node.rack: rack314
6. 默认情况下,多个节点可以在同一个安装路径启动,如果你想让你的es只启动一个节点,可以进行如下设置:
node.max_local_storage_nodes: 1
7. 设置一个索引的碎片数量,默认值为5:
index.number_of_shards: 5
8. 设置一个索引可被复制的数量,默认值为1:
index.number_of_replicas: 1
当你想要禁用公布式时,你可以进行如下设置:
index.number_of_shards: 1
index.number_of_replicas: 0
这两个属性的设置直接影响集群中索引和搜索操作的执行。假设你有足够的机器来持有碎片和复制品,那么可以按如下规则设置这两个值:
1) 拥有更多的碎片可以提升索引执行能力,并允许通过机器分发一个大型的索引;
2) 拥有更多的复制器能够提升搜索执行能力以及集群能力。
对于一个索引来说,number_of_shards只能设置一次,而number_of_replicas可以使用索引更新设置API在任何时候被增加或者减少。
ElasticSearch关注加载均衡、迁移、从节点聚集结果等等。可以尝试多种设计来完成这些功能。
可以连接http://localhost:9200/A/_status来检测索引的状态。
9. 配置文件所在的位置,即elasticsearch.yml和logging.yml所在的位置:
path.conf: /path/to/conf
10. 分配给当前节点的索引数据所在的位置:
path.data: /path/to/data
可以可选择的包含一个以上的位置,使得数据在文件级别跨越位置,这样在创建时就有更多的自由路径,如:
path.data: /path/to/data1,/path/to/data2
11. 临时文件位置:
path.work: /path/to/work
12. 日志文件所在位置:
path.logs: /path/to/logs
13. 插件安装位置:
path.plugins: /path/to/plugins
14. 插件托管位置,若列表中的某一个插件未安装,则节点无法启动:
plugin.mandatory: mapper-attachments,lang-groovy
15. JVM开始交换时,ElasticSearch表现并不好:你需要保障JVM不进行交换,可以将bootstrap.mlockall设置为true禁止交换:
bootstrap.mlockall: true
请确保ES_MIN_MEM和ES_MAX_MEM的值是一样的,并且能够为ElasticSearch分配足够的内在,并为系统操作保留足够的内存。
16. 默认情况下,ElasticSearch使用0.0.0.0地址,并为http传输开启9200-9300端口,为节点到节点的通信开启9300-9400端口,也可以自行设置IP地址:
network.bind_host: 192.168.0.1
17. publish_host设置其他节点连接此节点的地址,如果不设置的话,则自动获取,publish_host的地址必须为真实地址:
network.publish_host: 192.168.0.1
18. bind_host和publish_host可以一起设置:
network.host: 192.168.0.1
19. 可以定制该节点与其他节点交互的端口:
transport.tcp.port: 9300
20. 节点间交互时,可以设置是否压缩,转为为不压缩:
transport.tcp.compress: true
21. 可以为Http传输监听定制端口:
http.port: 9200
22. 设置内容的最大长度:
http.max_content_length: 100mb
23. 禁止HTTP
http.enabled: false
24. 网关允许在所有集群重启后持有集群状态,集群状态的变更都会被保存下来,当第一次启用集群时,可以从网关中读取到状态,默认网关类型(也是推荐的)是local:
gateway.type: local
25. 允许在N个节点启动后恢复过程:
gateway.recover_after_nodes: 1
26. 设置初始化恢复过程的超时时间:
gateway.recover_after_time: 5m
27. 设置该集群中可存在的节点上限:
gateway.expected_nodes: 2
28. 设置一个节点的并发数量,有两种情况,一种是在初始复苏过程中:
cluster.routing.allocation.node_initial_primaries_recoveries: 4
另一种是在添加、删除节点及调整时:
cluster.routing.allocation.node_concurrent_recoveries: 2
29. 设置复苏时的吞吐量,默认情况下是无限的:
indices.recovery.max_size_per_sec: 0
30. 设置从对等节点恢复片段时打开的流的数量上限:
indices.recovery.concurrent_streams: 5
31. 设置一个集群中主节点的数量,当多于三个节点时,该值可在2-4之间:
discovery.zen.minimum_master_nodes: 1
32. 设置ping其他节点时的超时时间,网络比较慢时可将该值设大:
discovery.zen.ping.timeout: 3s
http://elasticsearch.org/guide/reference/modules/discovery/zen.html上有更多关于discovery的设置。
33. 禁止当前节点发现多个集群节点,默认值为true:
discovery.zen.ping.multicast.enabled: false
34. 设置新节点被启动时能够发现的主节点列表(主要用于不同网段机器连接):
discovery.zen.ping.unicast.hosts: [“host1”, “host2:port”, “host3[portX-portY]”]
35.设置是否可以通过正则或者_all删除或者关闭索引
action.destructive_requires_name 默认false 允许 可设置true不允许
Elasticsearch 的工作原理是什么?
原始数据会从多个来源(包括日志、系统指标和网络应用程序)输入到 Elasticsearch 中。数据采集指在 Elasticsearch 中进行索引之前解析、标准化并充实这些原始数据的过程。这些数据在 Elasticsearch 中索引完成之后,用户便可针对他们的数据运行复杂的查询,并使用聚合来检索自身数据的复杂汇总。在 Kibana 中,用户可以基于自己的数据创建强大的可视化,分享仪表板,并对 Elastic Stack 进行管理。
Elasticsearch 索引是什么?
Elasticsearch 索引指相互关联的文档集合。Elasticsearch 会以 JSON 文档的形式存储数据。每个文档都会在一组键(字段或属性的名称)和它们对应的值(字符串、数字、布尔值、日期、数值组、地理位置或其他类型的数据)之间建立联系。
Elasticsearch 使用的是一种名为倒排索引的数据结构,这一结构的设计可以允许十分快速地进行全文本搜索。倒排索引会列出在所有文档中出现的每个特有词汇,并且可以找到包含每个词汇的全部文档。
在索引过程中,Elasticsearch 会存储文档并构建倒排索引,这样用户便可以近实时地对文档数据进行搜索。索引过程是在索引 API 中启动的,通过此 API 您既可向特定索引中添加 JSON 文档,也可更改特定索引中的 JSON 文档。
为何使用 Elasticsearch?
Elasticsearch 很快。由于 Elasticsearch 是在 Lucene 基础上构建而成的,所以在全文本搜索方面表现十分出色。Elasticsearch 同时还是一个近实时的搜索平台,这意味着从文档索引操作到文档变为可搜索状态之间的延时很短,一般只有一秒。因此,Elasticsearch 非常适用于对时间有严苛要求的用例,例如安全分析和基础设施监测。
Elasticsearch 具有分布式的本质特征。Elasticsearch 中存储的文档分布在不同的容器中,这些容器称为分片,可以进行复制以提供数据冗余副本,以防发生硬件故障。Elasticsearch 的分布式特性使得它可以扩展至数百台(甚至数千台)服务器,并处理 PB 量级的数据。
Elasticsearch 包含一系列广泛的功能。除了速度、可扩展性和弹性等优势以外,Elasticsearch 还有大量强大的内置功能(例如数据汇总和索引生命周期管理),可以方便用户更加高效地存储和搜索数据。
Elastic Stack 简化了数据采集、可视化和报告过程。通过与 Beats 和 Logstash 进行集成,用户能够在向 Elasticsearch 中索引数据之前轻松地处理数据。同时,Kibana 不仅可针对 Elasticsearch 数据提供实时可视化,同时还提供 UI 以便用户快速访问应用程序性能监测 (APM)、日志和基础设施指标等数据。
Elasticsearch 提供强大且全面的 REST API 集合,这些 API 可用来执行各种任务,例如检查集群的运行状况、针对索引执行 CRUD(创建、读取、更新、删除)和搜索操作,以及执行诸如筛选和聚合等高级搜索操作。
Elasticsearch 分词
分词分为读时分词和写时分词。
读时分词发生在用户查询时,ES 会即时地对用户输入的关键词进行分词,分词结果只存在内存中,当查询结束时,分词结果也会随即消失。而写时分词发生在文档写入时,ES 会对文档进行分词后,将结果存入倒排索引,该部分最终会以文件的形式存储于磁盘上,不会因查询结束或者 ES 重启而丢失。
写时分词器需要在 mapping 中指定,而且一经指定就不能再修改,若要修改必须新建索引。
分词一般在ES中有分词器处理。英文为Analyzer,它决定了分词的规则,Es默认自带了很多分词器,如:
Standard、english、Keyword、Whitespace等等。默认的分词器为Standard,通过它们各自的功能可组合
成你想要的分词规则。分词器具体详情可查看官网:分词器
另外,在常用的中文分词器、拼音分词器、繁简体转换插件。国内用的就多的分别是:
- 中文: https://github.com/medcl/elasticsearch-analysis-ik/releases/
- 拼音: https://github.com/medcl/elasticsearch-analysis-pinyin/releases/
- 简体/繁体转换:https://github.com/medcl/elasticsearch-analysis-stconvert/releases/
可在以上链接找到自己对于的elasticsearch版本安装插件。
使用javaApi连接es
maven依赖
<dependencies>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
</dependency>
<!--elasticsearch客户端-->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
</dependency>
</dependencies>
索引管理
@Service
public class EsIndexOperation {
@Resource
private RestHighLevelClient client ;
private final RequestOptions options = RequestOptions.DEFAULT;
/**
* 判断索引是否存在
*/
public boolean checkIndex (String index) {
try {
return client.indices().exists(new GetIndexRequest(index), options);
} catch (IOException e) {
e.printStackTrace();
}
return Boolean.FALSE ;
}
/**
* 创建索引
*/
public boolean createIndex (String indexName ,Map<String, Object> columnMap){
try {
if(!checkIndex(indexName)){
CreateIndexRequest request = new CreateIndexRequest(indexName);
if (columnMap != null && columnMap.size()>0) {
Map<String, Object> source = new HashMap<>();
source.put("properties", columnMap);
request.mapping(source);
}
this.client.indices().create(request, options);
return Boolean.TRUE ;
}
} catch (IOException e) {
e.printStackTrace();
}
return Boolean.FALSE;
}
/**
* 删除索引
*/
public boolean deleteIndex(String indexName) {
try {
if(checkIndex(indexName)){
DeleteIndexRequest request = new DeleteIndexRequest(indexName);
AcknowledgedResponse response = client.indices().delete(request, options);
return response.isAcknowledged();
}
} catch (Exception e) {
e.printStackTrace();
}
return Boolean.FALSE;
}
}
数据管理
这里在更新数据时,可以直接修改索引结构,在dataMap中放进新的字段即可。
@Service
public class EsDataOperation {
@Resource
private RestHighLevelClient client ;
private final RequestOptions options = RequestOptions.DEFAULT;
/**
* 写入数据
*/
public boolean insert (String indexName, Map<String,Object> dataMap){
try {
BulkRequest request = new BulkRequest();
request.add(new IndexRequest(indexName,"doc").id(dataMap.remove("id").toString())
.opType("create").source(dataMap,XContentType.JSON));
this.client.bulk(request, options);
return Boolean.TRUE ;
} catch (Exception e){
e.printStackTrace();
}
return Boolean.FALSE;
}
/**
* 批量写入数据
*/
public boolean batchInsert (String indexName, List<Map<String,Object>> userIndexList){
try {
BulkRequest request = new BulkRequest();
for (Map<String,Object> dataMap:userIndexList){
request.add(new IndexRequest(indexName,"doc").id(dataMap.remove("id").toString())
.opType("create").source(dataMap,XContentType.JSON));
}
this.client.bulk(request, options);
return Boolean.TRUE ;
} catch (Exception e){
e.printStackTrace();
}
return Boolean.FALSE;
}
/**
* 更新数据,可以直接修改索引结构
*/
public boolean update (String indexName, Map<String,Object> dataMap){
try {
UpdateRequest updateRequest = new UpdateRequest(indexName,"doc", dataMap.remove("id").toString());
updateRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
updateRequest.doc(dataMap) ;
this.client.update(updateRequest, options);
return Boolean.TRUE ;
} catch (Exception e){
e.printStackTrace();
}
return Boolean.FALSE;
}
/**
* 删除数据
*/
public boolean delete (String indexName, String id){
try {
DeleteRequest deleteRequest = new DeleteRequest(indexName,"doc", id);
this.client.delete(deleteRequest, options);
return Boolean.TRUE ;
} catch (Exception e){
e.printStackTrace();
}
return Boolean.FALSE;
}
}
查询操作
注意:查询总数的CountRequest语法,SearchRequest查询结果中数据转换语法,分页查询中需要指定偏移位置和分页大小。
@Service
public class EsQueryOperation {
@Resource
private RestHighLevelClient client ;
private final RequestOptions options = RequestOptions.DEFAULT;
/**
* 查询总数
*/
public Long count (String indexName){
// 指定创建时间
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
queryBuilder.must(QueryBuilders.termQuery("createTime", 1611378102795L));
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(queryBuilder);
CountRequest countRequest = new CountRequest(indexName);
countRequest.source(sourceBuilder);
try {
CountResponse countResponse = client.count(countRequest, options);
return countResponse.getCount();
} catch (Exception e) {
e.printStackTrace();
}
return 0L;
}
/**
* 查询集合
*/
public List<Map<String,Object>> list (String indexName) {
// 查询条件,指定时间并过滤指定字段值
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
queryBuilder.must(QueryBuilders.termQuery("createTime", 1611378102795L));
queryBuilder.mustNot(QueryBuilders.termQuery("name","北京-李四"));
sourceBuilder.query(queryBuilder);
SearchRequest searchRequest = new SearchRequest(indexName);
searchRequest.source(sourceBuilder);
try {
SearchResponse searchResp = client.search(searchRequest, options);
List<Map<String,Object>> data = new ArrayList<>() ;
SearchHit[] searchHitArr = searchResp.getHits().getHits();
for (SearchHit searchHit:searchHitArr){
Map<String,Object> temp = searchHit.getSourceAsMap();
temp.put("id",searchHit.getId()) ;
data.add(temp);
}
return data;
} catch (Exception e) {
e.printStackTrace();
}
return null ;
}
/**
* 分页查询
*/
public List<Map<String,Object>> page (String indexName,Integer offset,Integer size) {
// 查询条件,指定时间并过滤指定字段值
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.from(offset);
sourceBuilder.size(size);
sourceBuilder.sort("createTime", SortOrder.DESC);
SearchRequest searchRequest = new SearchRequest(indexName);
searchRequest.source(sourceBuilder);
try {
SearchResponse searchResp = client.search(searchRequest, options);
List<Map<String,Object>> data = new ArrayList<>() ;
SearchHit[] searchHitArr = searchResp.getHits().getHits();
for (SearchHit searchHit:searchHitArr){
Map<String,Object> temp = searchHit.getSourceAsMap();
temp.put("id",searchHit.getId()) ;
data.add(temp);
}
return data;
} catch (Exception e) {
e.printStackTrace();
}
return null ;
}
}
五、排序方式
排序除了常规的指定字段升序降序规则之外,还可以基于原生的脚本语法,基于自定义规则排序让一些特定的数据沉底或者置顶。
@Service
public class EsSortOperation {
@Resource
private RestHighLevelClient client ;
private final RequestOptions options = RequestOptions.DEFAULT;
/**
* 排序规则
*/
public List<Map<String,Object>> sort (String indexName) {
// 先升序时间,在倒序年龄
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.sort("createTime", SortOrder.ASC);
sourceBuilder.sort("age",SortOrder.DESC) ;
SearchRequest searchRequest = new SearchRequest(indexName);
searchRequest.source(sourceBuilder);
try {
SearchResponse searchResp = client.search(searchRequest, options);
List<Map<String,Object>> data = new ArrayList<>() ;
SearchHit[] searchHitArr = searchResp.getHits().getHits();
for (SearchHit searchHit:searchHitArr){
Map<String,Object> temp = searchHit.getSourceAsMap();
temp.put("id",searchHit.getId()) ;
data.add(temp);
}
return data;
} catch (Exception e) {
e.printStackTrace();
}
return null ;
}
/**
* 自定义排序规则
*/
public List<Map<String,Object>> defSort (String indexName) {
// 指定置换顺序的规则
// [age 12-->60]\[age 19-->10]\[age 13-->30]\[age 18-->40],age其他值忽略为1
Script script = new Script("def _ageSort = doc['age'].value == 12?60:" +
"(doc['age'].value == 19?10:" +
"(doc['age'].value == 13?30:" +
"(doc['age'].value == 18?40:1)));" + "_ageSort;");
ScriptSortBuilder sortBuilder = SortBuilders.scriptSort(script,ScriptSortBuilder.ScriptSortType.NUMBER);
sortBuilder.order(SortOrder.ASC);
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.sort(sortBuilder);
SearchRequest searchRequest = new SearchRequest(indexName);
searchRequest.source(sourceBuilder);
try {
SearchResponse searchResp = client.search(searchRequest, options);
List<Map<String,Object>> data = new ArrayList<>() ;
SearchHit[] searchHitArr = searchResp.getHits().getHits();
for (SearchHit searchHit:searchHitArr){
Map<String,Object> temp = searchHit.getSourceAsMap();
temp.put("id",searchHit.getId()) ;
data.add(temp);
}
return data;
} catch (Exception e) {
e.printStackTrace();
}
return null ;
}
}
集群部署elasticsearch简介
单台elasticsearch提供服务,往往都有最大的负载能力,超过这个阈值,服务器性能就会大大降低甚至不可用,所以生成环境中,一般都是运行在指定服务器集群中。
集群cluster:一个集群就是由一个或者多个服务器节点组织在一起,共同持有整个数据,并一起提供索引和搜索服务。一个Elasticsearch集群有一个唯一的名字标识,整个名字默认就是elasticsearch。整个名字很重要,因为一个节点只能通过指定某个集群的名字来加入集群。文章来源:https://www.toymoban.com/news/detail-421411.html
节点Node:集群中包含很多的服务器,一个节点就是其中的一个服务器。作为集群的一部分,它存储数据,参与集群的索引和搜索功能。一个节点也是由一个表示来决定的,一个节点可以通过配置集群名称的方式来加入一个指定的集群文章来源地址https://www.toymoban.com/news/detail-421411.html
到了这里,关于全文搜索引擎 Elasticsearch详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!