ElasticSearch
Elasticsearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java语言开发的,并作为Apache许可条款下的开放源码发布,是一种流行的企业级搜索引擎。Elasticsearch用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。官方客户端在Java、.NET(C#)、PHP、Python、Apache Groovy、Ruby和许多其他语言中都是可用的。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr,也是基于Lucene。
ES目录结构
bin 启动文件
config 配置文件
log4j2 日志配置文件
jvm.options java虚拟机相关配置
elasticsearch.yml elasticsearch配置文件 默认9200端口
lib 相关jar包
logs 日志
modules 功能模块
plugins 插件
Docker下安装
默认端口: 9200 , 9300, kibana连接端口: 5601
docker run -it -e "discovery.type=single-node" --name elasticsearch -d -p 9200:9200 -p 9300:9300 -p 5601:5601 elasticsearch
在docker下安装需要映射以上两个端口, 启动后可通过浏览器访问, 出现以下信息则说明启动成功
{
"name" : "0F6pJCO",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "Ra_qBBOnQumXsBrpN5nMrQ",
"version" : {
"number" : "5.6.12",
"build_hash" : "cfe3d9f",
"build_date" : "2018-09-10T20:12:43.732Z",
"build_snapshot" : false,
"lucene_version" : "6.6.1"
},
"tagline" : "You Know, for Search"
}
ELK
"ELK"是三个开源项目的首字母缩写,这三个项目分别是:Elasticsearch、Logstash 和 Kibana。Elasticsearch 是一个搜索和分析引擎。Logstash 是服务器端数据处理管道,能够同时从多个来源采集数据,转换数据,然后将数据发送到诸如 Elasticsearch 等“存储库”中。Kibana 则可以让用户在 Elasticsearch 中使用图形和图表对数据进行可视化。
Elastic Stack 是 ELK Stack 的更新换代产品。
安装Kibana
Kibana版本需要和ES版本一致
默认端口:5601
可通过浏览器访问, 进入默认界面则启动成功
docker run -it -d -e ELASTICSEARCH_URL=http://127.0.0.1:9200 --name kibana --network=container:elasticsearch kibana
ES核心概念
ES是面向文档, 数据以JSON
形式存储
关系型数据库和ES的对比
Relationl DB | Elasticsearch |
---|---|
数据库(database) | 索引(indices) |
表(tables) | types |
行(rows) | documents |
字段(columns) | fields |
IK分词器
IK Analyzer是一个开源的,基于java语言开发的轻量级的中文分词工具包。。最初,它是以开源项目Luence为应用主体的,结合词典分词和文法分析算法的中文分词组件。
安装参考:https://www.cnblogs.com/szwdun/p/10664348.html
分词效果
ik_smart
为最小切分
GET _analyze
{
"analyzer": "ik_smart",
"text": "中华人民共和国"
}
//结果
{
"tokens" : [
{
"token" : "中华人民共和国",
"start_offset" : 0,
"end_offset" : 7,
"type" : "CN_WORD",
"position" : 0
}
]
}
ik_max_word
为最细密度切分
GET _analyze
{
"analyzer": "ik_max_word",
"text": "中华人民共和国"
}
//结果
{
"tokens" : [
{
"token" : "中华人民共和国",
"start_offset" : 0,
"end_offset" : 7,
"type" : "CN_WORD",
"position" : 0
},
{
"token" : "中华人民",
"start_offset" : 0,
"end_offset" : 4,
"type" : "CN_WORD",
"position" : 1
},
...
]
}
自定义分词
在es的/plugin/ik/config/
目录下添加自己的dic
词典文件
在IKAnalyzer.cfg.xml
中添加自己的配置
重启ES生效
Rest风格说明
一种软件架构风格, 只是提供了一组设计原则和约束条件. 它主要用于客户端和服务器交互类的软件. 基于这个风格设计的软件可以更简介, 更有层次, 更易于实现缓存等机制.
基本Rest命令说明
method | url地址 | 描述 |
---|---|---|
PUT | localhost:9200/索引名称/类型名称/文档id | 创建文档(指定文档id) |
POST | localhost:9200/索引名称/类型名称 | 创建文档(随机文档id) |
POST | localhost:9200/索引名称/类型名称/文档id/_update | 修改文档 |
DELETE | localhost:9200/索引名称/类型名称/文档id | 删除文档 |
GET | localhost:9200/索引名称/类型名称/文档id | 通过id查询文档 |
POST | localhost:9200/索引名称/类型名称/_search | 查询所有数据 |
基本类型说明
类型 | 关键字 |
---|---|
字符串类型 | text , keyword |
数值类型 | long , integer , short , byte , double , float , half_float , scaled_folat |
日期类型 | date |
布尔类型 | boolean |
二进制类型 | binary |
… | … |
创建索引并指定类型
PUT /test2
{
"mappings": { //映射
"properties": {
"name": { //字段
"type": "text" //类型
},
"age": {
"type": "integer"
},
"birthday": {
"type": "date"
}
}
}
}
结果:
{
"acknowledged" : true,
"shards_acknowledged" : true,
"index" : "test2"
}
基础测试
-
创建一个索引
PUT /test1/type1/1 { "name": "乔布斯", "age": "50" }
结果:
{ "_index" : "test1", //索引 "_type" : "type1", //类型 "_id" : "1", //id "_version" : 1, //版本 "result" : "created", //操作 "_shards" : { "total" : 2, //索引中文档数 "successful" : 1, //是否成功 "failed" : 0 }, "_seq_no" : 1, "_primary_term" : 1 }
-
获取es当前信息
GET _cat
-
修改数据
doc
中指定需要修改的数据POST /test2/_doc/1/_update { "doc": { "name": "root" } }
-
删除数据
DELETE /test1
-
查询数据
查询索引中所有的文档
POST /blog/user/_search
复杂查询: 使用json构建
GET /blog/user/_search { "query": { //查询 "match": { //匹配 "name": "root" } }, "_source":["name","desc"], //显示部分属性(结果过滤) "sort":{ //排序 "age": { "order": "desc" //升序(asc,降序) } }, //分页 "from": 0, //开始数据 "size": 2 //每页大小 }
精确查询
must
中所有条件都要符合(and)should
中满足其一(or)must_not
反选(not)GET /blog/user/_search { "query": { "bool": { "must": [ //must中所有条件都要符合(and) { "match": { "name": "root" } }, { "match": { "age": 23 } } ] } } }
过滤器
GET /blog/user/_search { "query": { "bool": { "filter": [ { "range": { "age": { "gt": 20 //大于 "gte": 20, //大于等于 "lte": 23 //小于等于 "lt": 23 //小于 } } } ] } } }
精确查找
使用
trem
查询GET /blog/user/_search { "query": { "bool": { "should": [ { "term": { "name": "root" } } ] } } }
高亮查询
GET /blog/user/_search { "query": { "match": { "desc": "测试" } }, "highlight": { "pre_tags": "<small style='color:red'>", // 自定义前缀 "post_tags": "</small>", // 自定义后缀 "fields": { "desc": {} } } }
结果:
"hits" : [ { "_index" : "blog", "_type" : "user", "_id" : "4", "_score" : 0.98433626, "_source" : { "name" : "roo_test", "age" : 20, "desc" : "root的测试用户", "tags" : [ "哈哈哈", "hello", "world" ] }, "highlight" : { "desc" : [ "root的<small style='color:red'>测</small><small style='color:red'>试</small>用户" ] } }, ...
集成SpringBoot
依赖坐标
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
注意: restClient需和本地es版本保持一致
<!-- 自定义es版本依赖 保证和本地版本一致 -->
<elasticsearch.version>7.9.2</elasticsearch.version>
配置类
使用高版本rest客户端
@Configuration
public class ElasticSearchConfig {
@Bean
public RestHighLevelClient restHighLevelClient(){
return new RestHighLevelClient(
RestClient.builder(new HttpHost("192.168.154.128", 9200, "http")));
}
}
关于索引
创建索引
/**
* 创建索引
*/
@Test
public void createIndex() throws IOException {
//创建索引请求
CreateIndexRequest indexRequest = new CreateIndexRequest("blog");
//执行请求 -> 获得响应
CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(indexRequest, RequestOptions.DEFAULT);
System.out.println(createIndexResponse.isAcknowledged());
}
判断索引存在
/**
* 获取索引
* 判断索引是否存在
*/
@Test
public void existIndex() throws IOException {
//创建获取索引请求
GetIndexRequest getIndexRequest = new GetIndexRequest("blog");
//执行请求 -> 返回boolean值
boolean exists = restHighLevelClient.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
System.out.println(exists);
}
删除索引
/**
* 删除索引
*/
@Test
public void deleteIndex() throws IOException {
//创建删除索引请求
DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest("blog");
//执行请求
AcknowledgedResponse response = restHighLevelClient.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
System.out.println(response.isAcknowledged());
}
关于文档
添加文档
/**
* 添加文档
*/
@Test
public void createDocument() throws IOException {
//创建对象
UserInfo userInfo = new UserInfo("harlan", 23);
//创建索引请求
IndexRequest indexRequest = new IndexRequest("blog");
//设置规则
indexRequest.id("1");
indexRequest.timeout(TimeValue.timeValueSeconds(1));
indexRequest.timeout("1s");
//将数据放入请求中 json
indexRequest.source(JSON.toJSONString(userInfo), XContentType.JSON);
//客户端发送请求, 获取响应结果
IndexResponse response = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
System.out.println(response.status());
}
判断文档存在
/**
* 判断文档是否存在
*/
@Test
public void isExists() throws IOException {
GetRequest getRequest = new GetRequest("blog", "1");
boolean exists = restHighLevelClient.exists(getRequest, RequestOptions.DEFAULT);
System.out.println(exists);
}
获取文档信息
/**
*获取文档
*/
@Test
public void getDocument() throws IOException {
GetRequest getRequest = new GetRequest("blog", "1");
GetResponse response = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);
System.out.println(response.getSourceAsString());
}
更新文档信息
/**
* 更新文档
*/
@Test
public void updateDocument() throws IOException {
UpdateRequest updateRequest = new UpdateRequest("blog", "1");
updateRequest.timeout("1s");
UserInfo userInfo = new UserInfo("root", 20);
updateRequest.doc(JSON.toJSON(userInfo), XContentType.JSON);
UpdateResponse response = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
System.out.println(response.status());
}
删除文档
/**
* 删除文档
*/
@Test
public void deleteDocument() throws IOException {
DeleteRequest deleteRequest = new DeleteRequest("blog", "1");
DeleteResponse response = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
System.out.println(response.status());
}
批量操作
/**
* 批量操作
*/
@Test
public void bulkRequest() throws IOException {
BulkRequest bulkRequest = new BulkRequest();
bulkRequest.timeout("10s");
List<UserInfo> userInfoList = new ArrayList<>();
userInfoList.add(new UserInfo("harlan", 20));
userInfoList.add(new UserInfo("PenXiaoC",26));
userInfoList.add(new UserInfo("HuangBingY", 23));
userInfoList.add(new UserInfo("ChengXiaoL", 22));
//批处理请求
for (int i = 0; i < userInfoList.size(); i++) {
bulkRequest.add(new IndexRequest("blog")
.id(""+(i+1)).source(JSON.toJSONString(userInfoList.get(i)), XContentType.JSON));
}
//执行请求
BulkResponse responses = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
System.out.println(responses.status());
}
搜索
/**
* 搜索
*/
@Test
void search() throws IOException {
SearchRequest searchRequest = new SearchRequest("blog");
//构建查询
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//构建条件
TermQueryBuilder termQuery = QueryBuilders.termQuery("name", "harlan");
//放入查询构建
sourceBuilder.query(termQuery);
sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
//分页
sourceBuilder.from(0);
sourceBuilder.size(1);
//放入请求
searchRequest.source(sourceBuilder);
//执行请求
SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//获取内容
for (SearchHit hit : response.getHits().getHits()) {
System.out.println(hit.getSourceAsMap());
}
}