目录
4.3通过IK分词器实现拓展词库,以及屏蔽不需要的创建词条的词语
六、使用JavaRestClient实现创建、删除索引库,判断索引库是否存在
6.1、引入es的RestHighLevelClient依赖
6.2配置config文件,初始化RestHighLevelClient:
一、概念介绍
概念:
什么是ES?
- 从功能上来说,elasticsearchelasticsearchelasticsearch是一款非常强大的开源搜索引擎,可以帮助我们从海量数据中快速找到需要的内容,实现搜索、日志统计、分析、系统监控等功能
- 从架构上说,elasticsearch是elastic stack的核心,负责存储、搜索、分析数据。
什么是elastic stack?
- elasticsearch结合kibana、Logstash、Beats,也就是elastic stack(ELK)。被广泛应用在日志数据分析、实时监控等领域
ES能够实现对数据的快速搜索,主要原因就是它采用倒排索引的方式:
倒排索引中包含两部分内容:
- 词条词典(Term Dictionary):记录所有词条,以及词条与倒排列表(Posting List)之间的关系,会给词条创建索引,提高查询和插入效率
- 倒排列表(Posting List):记录词条所在的文档id、词条出现频率 、词条在文档中的位置等信息
- 文档id:用于快速获取文档
- 词条频率(TF):文档在词条出现的次数,用于评分
简单来说就是将一条条数据划分一个个文档,再对整个文档中的某些字段建立倒排索引,将字段按照语义划分成词语,再将每个不同的词语作为主键,对应的值就是文档的id,如下图:
ES搜索流程:
同时ES也是面向文档进行存储,可以是数据库中的一条商品数据,一个订单信息。
文档数据会被序列化为json格式后存储在elasticsearch中
索引:相同类型的文档的集合
映射( mapping ):索引中文档的字段约束信息,类似表的结构约束
下面为了加深读者对ES的认识,有关于elasticsearch和数据库的对比表格
|-----------|-------------------|----------------------------------------------------------|
| MySQL | Elasticsearch | 说明 |
| Table | Index | 索引(index),就是文档的集合,类似数据库的表(table) |
| Row | Document | 文档(Document),就是一条条的数据,类似数据库中的行(Row),文档都是JSON格式 |
| Column | Field | 字段(Field),就是JSON文档中的字段,类似数据库中的列(Column) |
| Schema | Mapping | Mapping(映射)是索引中文档的约束,例如字段类型约束。类似数据库的表结构(Schema) |
| SQL | DSL | DSL是elasticsearch提供的JSON风格的请求语句,用来操作elasticsearch,实现CRUD |架构对比:
Mysql:擅长事务类型操作,可以确保数据的安全和一致性
Elasticsearch:擅长海量数据的搜索、分析、计算
二、Elasticsearch的Docker容器安装
2.1拉取elasticsearch的镜像文件
默认拉取最新版本,内容较大可能拉取失败,可以提前在windows下载好,上传到linux中
docker pull docker.elastic.co/elasticsearch/elasticsearch
导入上传的镜像的tar包
docker load -i es.tar
2.2运行docker命令启动容器
这里指定运行内存大小为512M,读者可更更具需求自行变更,详细命令解释如下
docker run -d \
--name es \
-e "ES_JAVA_OPTS=-Xms512m -Xmx512m" \
-e "discovery.type=single-node" \
-v es-data:/usr/share/elasticsearch/data \
-v es-plugins:/usr/share/elasticsearch/plugins \
--privileged \
--network es-net \
-p 9200:9200 \
-p 9300:9300 \
elasticsearch:7.12.1
命令解释:
-e "cluster.name=es-docker-cluster"
:设置集群名称-e "http.host=0.0.0.0"
:监听的地址,可以外网访问-e "ES_JAVA_OPTS=-Xms512m -Xmx512m"
:内存大小-e "discovery.type=single-node"
:非集群模式-v es-data:/usr/share/elasticsearch/data
:挂载逻辑卷,绑定es的数据目录-v es-logs:/usr/share/elasticsearch/logs
:挂载逻辑卷,绑定es的日志目录-v es-plugins:/usr/share/elasticsearch/plugins
:挂载逻辑卷,绑定es的插件目录--privileged
:授予逻辑卷访问权--network es-net
:加入一个名为es-net的网络中,方便之后创建Kibana容器后,两者互相连接-p 9200:9200
:端口映射配置
2.3通过访问端口地址查看部署情况
查询如上图所示,则表示查询成功
三、安装Kibana容器
为了实现对elasticsearch可视化操作,我们需要使用Kibana,帮助我们搭建一个页面实现对es的操作
注意:Kibana和ES版本必须一致
3.1拉取Kibana镜像容器指令(默认拉取最新版本):
docker pull docker.elastic.co/kibana/kibana
3.2拉取完成后运行docker命令,部署Kibana:
docker run -d \
--name kibana \
-e ELASTICSEARCH_HOSTS=http://es:9200 \
--network=es-net \
-p 5601:5601 \
kibana:7.12.1
指令解释:
-
--network es-net
:加入一个名为es-net的网络中,与elasticsearch在同一个网络中 -
-e ELASTICSEARCH_HOSTS=http://es:9200"
:设置elasticsearch的地址,因为kibana已经与elasticsearch在一个网络,因此可以用容器名直接访问elasticsearch -
-p 5601:5601
:端口映射配置
3.3访问kibana提供的界面检查是否部署成功
四、配置中文分词器IK分词器
官方提供的分词器对中文的支持很不友好,所以我们需要引入第三方的IK分词器插件
ik分词器包含两种模式:
- ik_smart:最少切分,粗粒度
- ik_max_word:最细切分,细粒度
4.1在线安装IK插件
注意:IK分词器插件的版本需要对应自己的ES版本,比如我这里的7.12.1
官方插件下载地址:
# 进入容器内部
docker exec -it elasticsearch /bin/bash
# 在线下载并安装
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.12.1/elasticsearch-analysis-ik-7.12.1.zip
#退出
exit
#重启容器
docker restart elasticsearch
4.2离线安装
如果提前在官方网址下载好了对应的IK分词器,可通过上传到数据卷的方式完成安装
安装插件需要知道elasticsearch的plugins目录位置,而我们用了数据卷挂载,因此需要查看elasticsearch的数据卷目录,通过下面命令查看:
docker volume inspect es-plugins
地址:
将下载好的IK分词器的zip包解压成ik文件并上传到/var/lib/docker/volumes/es-plugins/_data文件内
重新启动容器完成插件安装
4.3通过IK分词器实现拓展词库,以及屏蔽不需要的创建词条的词语
要拓展ik分词器的词库,只需要修改一个ik分词器目录中的config目录中的IkAnalyzer.cfg.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>IK Analyzer 扩展配置</comment>
<!--用户可以在这里配置自己的扩展字典 -->
<entry key="ext_dict">ext.dic</entry>
<!--用户可以在这里配置自己的扩展停止词字典-->
<entry key="ext_stopwords">stopword.dic</entry>
<!--用户可以在这里配置远程扩展字典 -->
<!-- <entry key="remote_ext_dict">words_location</entry> -->
<!--用户可以在这里配置远程扩展停止词字典-->
<!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>
ext.dic文本文件格式示例:直接换行输入你想要添加的扩展词汇
stopword.dic文本文件格式如上
五、elasticsearch的DSL指令使用
在创建索引库中需要了解索引库的Mapping属性
mapping是对索引库中文档的约束,常见的mapping属性包括:
- type:字段数据类型,常见的简单类型有:
- 字符串:text(可分词的文本)、keyword(精确值,例如:品牌、国家、ip地址)
- 数值:long、integer、short、byte、double、float、
- 布尔:boolean
- 日期:date
- 对象:object
- index:是否创建索引,默认为true
- analyzer:使用哪种分词器
- properties:该字段的子字段
总结:
Mapping常见属性:
- type:数据类型
- index:是否索引
- analyzer:分词器
- properties:子字段
常见type类型:
- 字符串:text、keyword
- 数字:long、integer、short、byte、double、float
- 布尔:boolean
- 日期:date
- 对象:object
5.1创建索引库和mapping的DSL语句如下:
ES中通过Restful请求操作索引库、文档,所以第一行Kibana需要发送一段请求,请求中携带DSL语句完成创建demo索引库
PUT /demo
{
"mappings": {
"properties": {
"info":{
"type": "text",
"analyzer": "ik_smart"
},
"email":{
"type": "keyword",
"index": "false"
},
"name":{
"properties": {
"firstName": {
"type": "keyword"
}
}
},
// ... 略
}
}
}
5.2其他常见索引库操作指令:
查看索引库语法:
GET /替换为需要查询的索引库名称
删除索引库的语法:
DELETE /替换为需要查询的索引库名称
修改索引库语法
注意: 索引库和mapping一旦创建无法修改,但是可以添加新的字段,语法如下:
PUT /索引库名/_mapping
{
"properties": {
"新字段名":{
"type": "integer"
}
}
}
总结:
索引库操作
- 创建索引库:PUT /索引库名
- 查询索引库:GET /索引库名
- 删除索引库:DELETE /索引库名
- 添加字段:PUT /索引库名/_mapping
5.3使用DSL语句对文档数据进行操作
5.3.1新增文档
语法:
POST /索引库名/_doc/文档id
{
"字段1": "值1",
"字段2": "值2",
"字段3": {
"子属性1": "值3",
"子属性2": "值4"
},
// ...
}
如:
注意:
- 插入文档时,es会检查文档中的字段是否有mapping,如果没有则按照默认mapping规则来创建索引。
- 如果默认mapping规则不符合你的需求,一定要自己设置字段mapping
5.3.2查看删除文档
查看文档语法:
GET /索引库名/_doc/文档id
删除索引库的语法:
DELETE /索引库名/_doc/文档id
5.3.3修改文档
方式一:全量修改语法:删除原文档数据,再新增本文档数据
PUT /索引库名/_doc/文档id
{
"字段1": "值1",
"字段2": "值2",
// ... 略
}
方式二:增量修改,修改指定字段值语法:
POST /索引库名/_update/文档id
{
"doc": {
"字段名": "新的值",
}
}
六、使用JavaRestClient实现创建、删除索引库,判断索引库是否存在
6.1、引入es的RestHighLevelClient依赖
XML
<properties>
<java.version>1.8</java.version>
<elasticsearch.version>7.12.1</elasticsearch.version>
</properties>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
</dependency>
6.2配置config文件,初始化RestHighLevelClient:
XML
@Configuration
public class ClientConfiguration {
@Bean
public RestHighLevelClient client() {
return new RestHighLevelClient(RestClient
.builder(new HttpHost("192.168.150.128", 9200, "http")
));
}
}
6.3创建索引库
XML
@Test
void createIndex() throws IOException {
//1.创建Request对象
CreateIndexRequest request = new CreateIndexRequest("demo");
//2.准备请求的参数:DSL语句
request.source(HOTEL_CONSTANT, XContentType.JSON);
//3.发送请求
client.indices().create(request, RequestOptions.DEFAULT);
}
6.4删除索引库
XML
@Test
void deleteIndex() throws IOException {
DeleteIndexRequest request = new DeleteIndexRequest("demo");
client.indices().delete(request, RequestOptions.DEFAULT);
}
6.5获取索引库
XML
@Test
void getIndex() throws IOException {
GetIndexRequest request = new GetIndexRequest("demo");
boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
log.info(exists ? "exists" : "not exists");
}
七、使用RestClient操作文档数据
7.1向索引库中添加文档数据
XML
@Test
void testAddDocument() throws IOException {
//准备数据,数据来源于数据库
Hotel hotel = hotelService.getById(36934L);
//转换为文档类型
HotelDoc hotelDoc = new HotelDoc(hotel);
//1.准备Request对象
IndexRequest request = new IndexRequest("hotel").id(hotelDoc.getId().toString());
//2.准备JSON数据
request.source(JSON.toJSONString(hotelDoc), XContentType.JSON);
//3.发送请求
client.index(request, RequestOptions.DEFAULT);
}
7.2获取文档对象并解析转换为实体对象
XML
@Test
void testGetDocument() throws IOException {
//准备Request对象
GetRequest hotel = new GetRequest("hotel", "36934");
//发送请求得到结果
GetResponse response = client.get(hotel, RequestOptions.DEFAULT);
//解析结果
String source = response.getSourceAsString();
//反序列化的hotel对象
HotelDoc hotelDoc = JSON.parseObject(source, HotelDoc.class);
log.info(hotelDoc.toString());
}
7.3更新文档对象数据
XML
@Test
void testUpdateDocument() throws IOException {
//准备Request对象
UpdateRequest request = new UpdateRequest("hotel", "36934");
//准备请求参数
request.doc(
"price", "99"
);
//发送请求
client.update(request, RequestOptions.DEFAULT);
}
7.4删除文档对象
XML
@Test
void testDeleteDocument() throws IOException {
DeleteRequest request = new DeleteRequest("hotel", "36934");
client.delete(request, RequestOptions.DEFAULT);
}
7.5实现批量插入文档对象
XML
@Test
void testBulk() throws IOException {
//查询所有酒店数据
List<Hotel> hotels = hotelService.list();
//创建request对象
BulkRequest bulkRequest = new BulkRequest();
//将hotel对象转换为hotelDoc对象
for (Hotel hotel : hotels) {
HotelDoc hotelDoc = new HotelDoc(hotel);
bulkRequest.add(new IndexRequest("hotel").id(hotelDoc.getId().toString())
.source(JSON.toJSONString(hotelDoc), XContentType.JSON));
}
//发送请求信息
client.bulk(bulkRequest, RequestOptions.DEFAULT);
}