微信公众号:码农私塾
关注可获得更多编程知识分享
如果你觉得文章对你有帮助,欢迎赞赏
目录
ElasticSerach简介ElasticSerach的应用场景ElasticSerach基本概念端口索引(Index)类型(Type)文档(Document)映射(Mapping)分片(Shards)副本(Replicas)docker-compose安装Elasticsearch集群docker-compose文件集群节点配置文件IK分词器java客户端操作Elasticsearch索引操作文档操作文档搜索总结
ElasticSerach简介
ElasticSerach简称为ES,是一个开源的高拓展的分布式全文搜索引擎,也是ELK技术的核心,可以近乎实时的存储,检索数据,可以处理PB级别的海量数据,提供了RESTful的http接口,各种编程语言都可以访问操作ES.
与传统sql数据库的差别在于,ES采用倒排索引,将存储的值使用算法分词,每个分词会记录包含这个分词的文档id,查找时 根据输入的关键词 查找倒排索引 快速定位到满足条件的数据 然后计算匹配度得到分值 用来排序结果
ElasticSerach的应用场景
Google,百度等网站搜索,它们都是根据网页中的关键字生成索引,我们在搜索的时候输入关键字,它们会将该关键字即索引匹配到的所有网页返回;还有常见的项目中应用日志的搜索等等。对于这些非结构化的数据文本,关系型数据库搜索不是能很好的支持。一般传统数据库,全文检索都实现的很鸡肋,因为一般也没人用数据库存文本字段。进行全文检索需要扫描整个表,如果数据量大的话即使对 SQL 的语法优化,也收效甚微。建 立了索引,但是维护起来也很麻烦,对于insert和update 操作都会重新构建索引。基于以上原因可以分析得出,在一些生产环境中,使用常规的搜索方式,性能是非常差
搜索的数据对象是大量的非结构化的文本数据。
文件记录量达到数十万或数百万个甚至更多。
支持大量基于交互式文本的查询。
需求非常灵活的全文搜索查询。
对高度相关的搜索结果的有特殊需求,但是没有可用的关系数据库可以满足。
这里说到的全文搜索引擎指的是目前广泛应用的主流搜索引擎。它的工作原理是计算机 索引程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的 次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反 馈给用户的检索方式。这个过程类似于通过字典中的检索字表查字的过程
ElasticSerach基本概念
端口
ES启动后会默认使用两个端口9200和9300,9200是提供Restful风格接口的端口,9300用于集群节点内部通信
索引(Index)
一个索引就是一个拥有几分相似特征的文档的集合。比如说,你可以有一个客户数据的 索引,另一个产品目录的索引,还有一个订单数据的索引。一个索引由一个名字来标识(必 须全部是小写字母),并且当我们要对这个索引中的文档进行索引、搜索、更新和删除的时 候,都要使用到这个名字。在一个集群中,可以定义任意多的索引。能搜索的数据必须索引,这样的好处是可以提高查询速度,比如:新华字典前面的目录 就是索引的意思,目录可以提高查询速度。
Elasticsearch 索引的精髓:一切设计都是为了提高搜索的性能
类型(Type)
在一个索引中,你可以定义一种或多种类型。一个类型是你的索引的一个逻辑上的分类/分区,其语义完全由你来定。通常,会为具 有一组共同字段的文档定义一个类型,5.x版本支持多种类型,6.x支持一种类型,7.x以后不支持自定义类型默认类型为_doc
文档(Document)
一个文档是一个可被索引的基础信息单元,也就是一条数据 比如:你可以拥有某一个客户的文档,某一个产品的一个文档,当然,也可以拥有某个 订单的一个文档。文档以 JSON(Javascript Object Notation)格式来表示,而 JSON 是一个 到处存在的互联网数据交互格式。在一个 index或者type 里面,你可以存储任意多的文档。
映射(Mapping)
mapping 是处理数据的方式和规则方面做一些限制,如:某个字段的数据类型、默认值、 分析器、是否被索引等等。这些都是映射里面可以设置的,类似数据库的表结构限制一样,是建立在索引上的
分片(Shards)
一个索引可以存储超出单个节点硬件限制的大量数据。比如,一个具有 10 亿文档数据 的索引占据 1TB 的磁盘空间,而任一节点都可能没有这样大的磁盘空间。或者单个节点处 理搜索请求,响应太慢。为了解决这个问题,Elasticsearch 提供了将索引划分成多份的能力, 每一份就称之为分片。当你创建一个索引的时候,你可以指定你想要的分片的数量。每个分片本身也是一个功能完善并且独立的“索引”,这个“索引”可以被放置到集群中的任何节点上,有两个好处
允许你水平分割 / 扩展你的内容容量
允许你在分片之上进行分布式的、并行的操作,进而提高性能/吞吐量
数据的存储具体哪一个分片上的路由功能,由ES的分片算法决定,默认是hash(_id)%分片数量,也可以指定使用某个字段的值来进行hash运算
副本(Replicas)
在一个网络或者云的环境下,随时可能有某一个节点故障导致无法提供服务,这时候就需要故障转移机制,Elasticsearch 可以在创建索引时指定分片数量和副本数量 默认分片和副本数量都是1 副本数量可以随时修改,分片可以读写,副本只能读取 可以根据集群机器情况设置副本数量 提高吞吐量,
并且ES不允许分片和副本在同一个节点存储,所以一个集群至少得有2个节点
docker-compose安装Elasticsearch集群
docker-compose文件
1version: "3"
2services:
3 es1:
4 image: elasticsearch:7.14.2
5 container_name: es1
6 environment:
7 - "ES_JAVA_OPTS=-Xms512M -Xmx512M" #配置jvm堆大小
8 volumes: #挂载配置文件 和数据目录
9 - E:\dockerData\elasticSearchCluster\es1\conf\elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
10 - E:\dockerData\elasticSearchCluster\es1\data:/usr/share/elasticsearch/data
11 - E:\dockerData\elasticSearchCluster\es1\plugins:/usr/share/elasticsearch/plugins
12 ports: #映射宿主机端口到容器端口
13 - 9200:9200
14 - 9300:9300
15 expose: #暴露这个端口
16 - 9200
17 es2:
18 image: elasticsearch:7.14.2
19 container_name: es2
20 environment:
21 - "ES_JAVA_OPTS=-Xms512M -Xmx512M" #配置jvm堆大小
22 volumes: #挂载配置文件 和数据目录
23 - E:\dockerData\elasticSearchCluster\es2\conf\elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
24 - E:\dockerData\elasticSearchCluster\es2\data:/usr/share/elasticsearch/data
25 - E:\dockerData\elasticSearchCluster\es2\plugins:/usr/share/elasticsearch/plugins
26 ports: #映射宿主机端口到容器端口
27 - 9201:9200
28 - 9301:9300
29 expose: #暴露这个端口
30 - 9201
31 depends_on:
32 - es1
33 es3:
34 image: elasticsearch:7.14.2
35 container_name: es3
36 environment:
37 - "ES_JAVA_OPTS=-Xms512M -Xmx512M" #配置jvm堆大小
38 volumes: #挂载配置文件 和数据目录
39 - E:\dockerData\elasticSearchCluster\es3\conf\elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
40 - E:\dockerData\elasticSearchCluster\es3\data:/usr/share/elasticsearch/data
41 - E:\dockerData\elasticSearchCluster\es3\plugins:/usr/share/elasticsearch/plugins
42 ports: #映射宿主机端口到容器端口
43 - 9202:9200
44 - 9302:9300
45 expose: #暴露这个端口
46 - 9202
47 depends_on:
48 - es2
集群节点配置文件
1cluster.name: "esCluster"
2node.name: "es1"
3node.master: true #是否有资格为主节点
4node.data: true #节点是否存储数据
5http.cors.enabled: true #开启跨域访问 elasticSearch-head插件需要开启此功能
6http.cors.allow-origin: "*"
7cluster.initial_master_nodes: ["es1"] #集群初始化默认主节点
8network.host: 0.0.0.0
9discovery.zen.minimum_master_nodes: 2
10discovery.zen.ping.unicast.hosts: ["es1:9300", "es2:9301", "es3:9302"]#集群所有节点通信地址
IK分词器
ES是全文搜索引擎会建立倒排索引,就会涉及到将存储的文本进行拆分,默认的分词器不适合中文,IK分词器就是专门针对中文进行分词,下载地址
1https://github.com/medcl/elasticsearch-analysis-ik/releases
选择和es对应的版本下载即可,解压成文件夹放到es的plugins目录下即可,启动es会加载
IK分词器提供两种分词类型
ik_max_word:会将文本做最细粒度的拆分
ik_smart:会将文本做最粗粒度的拆分
如果需要自定义某几个字作为一个词,不想被拆分也可以自定义字典,在建立索引映射时可以给字段设置需要使用的分词器
java客户端操作Elasticsearch
es支持多种语言客户端包括java,目前新版主要使用Java High Level REST Client进行访问,Spring Data也提供了对应的子项目 spring data elasticSearch 以dao接口的设计模式 对Java High Level REST Client进行了封装 可以和使用操作sql数据库一样进行使用
索引操作
对于索引的操作都是封装在IndicesClient这个对象的方法,通过传入例如CreateIndexRequest,GetMappingsRequest这样的参数来实现具体的操作 而这个IndicesClient对象通过RestHighLevelClient的indices()方法获得
创建索引
1 RestHighLevelClient highLevelClient=new RestHighLevelClient(RestClient.builder(new HttpHost("localhost", 9200, "http")));
2
3//指定索引名
4CreateIndexRequest request=new CreateIndexRequest("test");
5// 设置分片以及副本
6request.settings(Settings.builder()
7 .put("index.number_of_shards", 3)
8 .put("index.number_of_replicas", 2)
9);
10//设置索引映射
11request.mapping("映射设置的json格式字符串",XContentType.JSON);
12 CreateIndexResponse createIndexResponse = highLevelClient.indices().create(request, RequestOptions.DEFAULT);
13 //创建状态
14 createIndexResponse.isAcknowledged()
查询索引
1 RestHighLevelClient highLevelClient=new RestHighLevelClient(RestClient.builder(new HttpHost("localhost", 9200, "http")));
2 //指定索引名
3 GetIndexRequest request=new GetIndexRequest("test");
4 GetIndexResponse getIndexResponse = highLevelClient.indices().get(request, RequestOptions.DEFAULT);
5 //获取索引分片和副本信息 以及映射信息
6 System.out.println(getIndexResponse.getSetting("test","index.number_of_shards"));
7 System.out.println(getIndexResponse.getSetting("test","index.number_of_replicas"));
8 System.out.println(getIndexResponse.getMappings().get("test").getSourceAsMap());
修改索引
1 RestHighLevelClient highLevelClient=new RestHighLevelClient(RestClient.builder(new HttpHost("localhost", 9200, "http")));
2//修改索引映射
3 PutMappingRequest request = new PutMappingRequest("test");
4 request.source("映射json格式字符串", XContentType.JSON);
5 highLevelClient.indices().putMapping(request,RequestOptions.DEFAULT);
6 //修改副本数量
7 UpdateSettingsRequest request2 = new UpdateSettingsRequest("test");
8 String settingKey = "index.number_of_replicas";
9 int settingValue = 1;
10 Settings settings =
11 Settings.builder()
12 .put(settingKey, settingValue)
13 .build();
14 request2.settings(settings);
15 highLevelClient.indices().putSettings(request2,RequestOptions.DEFAULT);
文档操作
创建文档
1 RestHighLevelClient highLevelClient=new RestHighLevelClient(RestClient.builder(new HttpHost("localhost", 9200, "http")));
2IndexRequest request=new IndexRequest("test");
3 //id 可不填 es自动生成
4 request.id(UUID.randomUUID().toString());
5 //设置要存储的文档值
6 request.source("{" +
7 "\"user\":\"kimchy\"," +
8 "\"postDate\":\"2013-01-30\"," +
9 "\"title\":\"trying out Elasticsearch\"" +
10 "}",XContentType.JSON);
11 IndexResponse index = highLevelClient.index(request, RequestOptions.DEFAULT);
12 //打印返回状态信息
13 System.out.println(index.toString());
批量创建
1 RestHighLevelClient highLevelClient=new RestHighLevelClient(RestClient.builder(new HttpHost("localhost", 9200, "http")));
2 //这个对象是用于执行批量操作的 不止可以批量新增 还可以修改 删除
3 BulkRequest request = new BulkRequest();
4 for (int i = 0; i < 10; i++) {
5 request.add(new IndexRequest("test").source("{" +
6 "\"user\":\"kimchy\"," +
7 "\"postDate\":\"2013-01-30\"," +
8 "\"title\":\"trying out Elasticsearch"+i+"\"" +
9 "}",XContentType.JSON));
10 }
11 BulkResponse bulk = highLevelClient.bulk(request, RequestOptions.DEFAULT);
修改文档
1 RestHighLevelClient highLevelClient=new RestHighLevelClient(RestClient.builder(new HttpHost("localhost", 9200, "http")));
2 //根据文档id修改 部分值
3 UpdateRequest request = new UpdateRequest("test", "49dec78f-cf84-481a-bc5e-b4f65c7e15cb");
4 request.doc("{\"title\":\"hello,world\"}",XContentType.JSON);
5 highLevelClient.update(request,RequestOptions.DEFAULT);
删除文档
1 RestHighLevelClient highLevelClient=new RestHighLevelClient(RestClient.builder(new HttpHost("localhost", 9200, "http")));
2//指定索引和文档id删除
3 DeleteRequest request=new DeleteRequest("test","49dec78f-cf84-481a-bc5e-b4f65c7e15cb");
4 highLevelClient.delete(request,RequestOptions.DEFAULT);
文档搜索
1RestHighLevelClient highLevelClient=new RestHighLevelClient(RestClient.builder(new HttpHost("localhost", 9200, "http")));
2 //创建搜索请求 并指定搜索的索引
3 SearchRequest request=new SearchRequest("test");
4 //创建搜索条件构建器
5 SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder();
6 //设置分页参数
7 searchSourceBuilder.from(0);
8 searchSourceBuilder.size(5);
9 //创建查询条件
10 QueryBuilder query = = QueryBuilders.matchAllQuery();
11 searchSourceBuilder.query(query);
12 request.source(searchSourceBuilder);
13 SearchResponse response = highLevelClient.search(request, RequestOptions.DEFAULT);
14 System.out.println(response.toString());
使用QueryBuilders这个工具类可以创建各种各类的QueryBuilder,可以用java代码的方式创建成es的Query DSL.相同的查询条件 可以参考官方文档
总结
ElasticSerach的版本更新非常快,并且API变动也比较大,所以很多时候都需要多去查看官网的文档






