1.Elasticsearch基本知识
1.基本认识和安装
Elasticsearch是由elastic公司开发的一套搜索引擎技术,它是elastic技术栈中的一部分。完整的技术栈包括:
-
Elasticsearch:用于数据存储、计算和搜索
-
Logstash/Beats:用于数据收集
-
Kibana:用于数据可视化
整套技术栈被称为ELK,经常用来做日志收集、系统监控和状态分析等等;
Kibana是elastic公司提供的用于操作Elasticsearch的可视化控制台。它的功能非常强大,包括:
-
对Elasticsearch数据的搜索、展示
-
对Elasticsearch数据的统计、聚合,并形成图形化报表、图形
-
对Elasticsearch的集群状态监控
-
它还提供了一个开发控制台(DevTools),在其中对Elasticsearch的Restful的API接口提供了语法提示
安装elasticsearch
执行如下代码,并访问9200端口
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 hm-net \-p 9200:9200 \-p 9300:9300 \elasticsearch:7.12.1
安装Kibana
执行如下代码,并访问5601端口
docker run -d \
--name kibana \
-e ELASTICSEARCH_HOSTS=http://es:9200 \
--network=hm-net \
-p 5601:5601 \
kibana:7.12.1
2.倒排索引
正向索引是最传统的,根据id索引的方式。但根据词条查询时,必须先逐条获取每个文档,然后判断文档中是否包含所需要的词条,是根据文档找词条的过程。
而倒排索引则相反,是先找到用户要搜索的词条,根据词条得到保护词条的文档的id,然后根据id获取文档。是根据词条找文档的过程。
正向索引
优点:
-
可以给多个字段创建索引
-
根据索引字段搜索、排序速度非常快
缺点:
根据非索引字段,或者索引字段中的部分词条查找时,只能全表扫描。
倒排索引
优点:
-
根据词条搜索、模糊搜索时,速度非常快
缺点:
-
只能给词条创建索引,而不是字段
-
无法根据字段做排序
3.IK分词器
Elasticsearch的关键就是倒排索引,而倒排索引依赖于对文档内容的分词,而分词则需要高效、精准的分词算法,IK分词器就是这样一个中文分词算法。
需要将中文分词器挂载到es的数据卷上
官方默认方式
POST /_analyze
{"analyzer": "standard","text": "世界人民大团结万岁"
}
IK分词器包含两种模式:
-
ik_smart
:智能语义切分 -
ik_max_word
:最细粒度切分
POST /_analyze
{"analyzer": "ik_smart","text": "世界人民大团结万岁"
}
POST /_analyze
{"analyzer": "ik_max_word","text": "世界人民大团结万岁"
}
有些词语字典里面没有,需要自己手动添加,还可以对某些字或词语不进行分词
在config目录下如图三个文件
添加自己的词语和不希望分词的词语即可
4.mysql和es的对比
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 |
2.索引库的操作
1.Mapping映射属性
Mapping是对索引库中文档的约束,常见的Mapping属性包括:
-
type
:字段数据类型,常见的简单类型有:-
字符串:
text
(可分词的文本)、keyword
(精确值,例如:品牌、国家、ip地址) -
数值:
long
、integer
、short
、byte
、double
、float
、 -
布尔:
boolean
-
日期:
date
-
对象:
object
-
-
index
:是否创建索引,默认为true
-
analyzer
:使用哪种分词器 -
properties
:该字段的子字段
2.索引库的CRUD
创建索引库
基本语法:
-
请求方式:
PUT
-
请求路径:
/索引库名
,可以自定义 -
请求参数:
mapping
映射
代码如下:
#新增
PUT /pxy
{"mappings": {"properties": {"info":{"type": "text","analyzer": "ik_smart"},"age":{"type": "byte"},"email":{"type": "keyword","index": false},"name":{"type": "object","properties": {"firstname":{"type": "keyword"},"lastname":{"type": "keyword","index":false}}}}}
}
查询索引库
基本语法:
-
请求方式:GET
-
请求路径:/索引库名
-
请求参数:无
代码如下:
#查询
GET /pxy
修改索引库
无法修改索引库,但是可以添加新的字段
#es不支持修改,但可以添加
PUT /pxy/_mapping
{"properties":{"age":{"type":"byte"}}
}
删除索引库
语法:
-
请求方式:DELETE
-
请求路径:/索引库名
-
请求参数:无
#删除
DELETE /pxy
3.文档的操作
1.文档的CRUD
增加数据
#新增数据
POST /pxy/_doc/1
{"info":"我是大帅哥","age":18,"email":"123456@qq.com","name":{"firstname":"潘","lastname":"xy"}
}
查询数据
#查询数据
GET /pxy/_doc/1
删除数据
#删除数据
DELETE /pxy/_doc/1
修改数据
分为全量修改和局部修改。全量修改是删除原来的数据在新增数据,局部修改只是把原来的数据修改掉。
#修改数据#全量修改
Put /pxy/_doc/1
{"info":"我是大帅哥","age":17,"email":"123456@qq.com","name":{"firstname":"p","lastname":"xy"}
}#局部修改
POST /pxy/_update/1
{"doc": {"info":"无敌是多么寂寞","name":{"firstname":"wd","lastname":"jm"}}
}
2.批量处理
一次处理多个请求
批处理采用POST请求,基本语法如下:
POST _bulk
{ "index" : { "_index" : "test", "_id" : "1" } }
{ "field1" : "value1" }
{ "delete" : { "_index" : "test", "_id" : "2" } }
{ "create" : { "_index" : "test", "_id" : "3" } }
{ "field1" : "value3" }
{ "update" : {"_id" : "1", "_index" : "test"} }
{ "doc" : {"field2" : "value2"} }
其中:
-
index
代表新增操作-
_index
:指定索引库名 -
_id
指定要操作的文档id -
{ "field1" : "value1" }
:则是要新增的文档内容
-
-
delete
代表删除操作-
_index
:指定索引库名 -
_id
指定要操作的文档id
-
-
update
代表更新操作-
_index
:指定索引库名 -
_id
指定要操作的文档id -
{ "doc" : {"field2" : "value2"} }
:要更新的文档字段
-
批量新增操作
POST /_bulk{"index":{"_index":"pxy","_id":"2"}}{"info":"我是大帅哥","age":17,"email":"123456@qq.com", "name":{"firstname":"p","lastname":"xy"}}{"index":{"_index":"pxy","_id":"3"}}{"info":"我是大帅哥","age":17,"email":"123456@qq.com", "name":{"firstnam:"p","lastname":"xy"}}
批量删除操作
POST /_bulk{"delete":{"_index":"pxy","_id":"2"}}{"delete":{"_index":"pxy","_id":"3"}}
4.用java程序操作es
1.注册RestHighLevelClient
在elasticsearch提供的API中,与elasticsearch一切交互都封装在一个名为RestHighLevelClient
的类中,必须先完成这个对象的初始化,建立与elasticsearch的连接。
导入依赖:
<dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId><version>7.12.1<version>
</dependency>
初始化代码如下:
RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://192.168.145.129:9200")
));
2.对索引进行操作
创建索引
@Testpublic void createindex() throws IOException {//准备request对象CreateIndexRequest request = new CreateIndexRequest("pxy");//准备请求参数request.source(MAPPING_TEMPLATE, XContentType.JSON);//发送请求体client.indices().create(request, RequestOptions.DEFAULT);}private final static String MAPPING_TEMPLATE="{\n" +" \"mappings\": {\n" +" \"properties\": {\n" +" \"id\": {\n" +" \"type\": \"keyword\"\n" +" },\n" +" \"name\":{\n" +" \"type\": \"text\",\n" +" \"analyzer\": \"ik_max_word\"\n" +" },\n" +" \"price\":{\n" +" \"type\": \"integer\"\n" +" },\n" +" \"stock\":{\n" +" \"type\": \"integer\"\n" +" },\n" +" \"image\":{\n" +" \"type\": \"keyword\",\n" +" \"index\": false\n" +" },\n" +" \"category\":{\n" +" \"type\": \"keyword\"\n" +" },\n" +" \"brand\":{\n" +" \"type\": \"keyword\"\n" +" },\n" +" \"sold\":{\n" +" \"type\": \"integer\"\n" +" },\n" +" \"commentCount\":{\n" +" \"type\": \"integer\",\n" +" \"index\": false\n" +" },\n" +" \"isAD\":{\n" +" \"type\": \"boolean\"\n" +" },\n" +" \"updateTime\":{\n" +" \"type\": \"date\"\n" +" }\n" +" }\n" +" }\n" +"}";
}
查询索引
@Testpublic void getindex() throws IOException {//准备request对象GetIndexRequest request = new GetIndexRequest("pxy");//发送请求体
// GetIndexResponse response = client.indices().get(request, RequestOptions.DEFAULT);
// System.out.println("返回参数"+response);//判断请求参数是否存在Boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);System.out.println("exists="+exists);}
删除索引
@Testpublic void deleteindex() throws IOException {//准备request对象DeleteIndexRequest request = new DeleteIndexRequest("pxy");//发送请求体client.indices().delete(request, RequestOptions.DEFAULT);}
3.对文档进行操作
新增文档
@Test
void testAddDocument() throws IOException {// 1.准备Request对象IndexRequest request = new IndexRequest("pxy").id("1");// 2.准备Json文档request.source({}, XContentType.JSON);// 3.发送请求client.index(request, RequestOptions.DEFAULT);
}
查询文档
@Test
void testGetDocumentById() throws IOException {// 1.准备Request对象GetRequest request = new GetRequest("pxy").id("1");// 2.发送请求GetResponse response = client.get(request, RequestOptions.DEFAULT);// 3.获取响应结果中的sourceString json = response.getSourceAsString();System.out.println("json= " + json);
}
删除文档
@Test
void testDeleteDocument() throws IOException {// 1.准备Request,两个参数,第一个是索引库名,第二个是文档idDeleteRequest request = new DeleteRequest("pxy", "1");// 2.发送请求client.delete(request, RequestOptions.DEFAULT);
}
修改文档
修改一共两种方式:
-
全量修改:本质是先根据id删除,再新增
-
局部修改:修改文档中的指定字段值
在RestClient的API中,全量修改与新增的API完全一致,判断依据是ID:
-
如果新增时,ID已经存在,则修改
-
如果新增时,ID不存在,则新增
这里不再赘述,我们主要关注局部修改的API即可。
@Test
void testUpdateDocument() throws IOException {// 1.准备RequestUpdateRequest request = new UpdateRequest("pxy", "1");// 2.准备请求参数request.doc("price", 58800,"commentCount", 1);// 3.发送请求client.update(request, RequestOptions.DEFAULT);
}
批量处理文档
@Test
void testBulk() throws IOException {// 1.创建RequestBulkRequest request = new BulkRequest();// 2.准备请求参数//新增文档request.add(new IndexRequest("items").id("1").source("json doc1", XContentType.JSON));request.add(new IndexRequest("items").id("2").source("json doc2", XContentType.JSON));//删除文档request.add(new DeleteRequest("items").id("2"));// 3.发送请求client.bulk(request, RequestOptions.DEFAULT);
}