持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第7天,点击查看活动详情
简介
Elaticsearch,简称为 ES,ES 是一个开源的高扩展的==分布式全文检索引擎==,它可以近乎==实时的存储、检索数据==;本身扩展性很好,可以扩展到上百台服务器,能够快速处理 PB 级别(大数据时代)的数据。
ES 的核心 Lucene 是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎(英文与德文两种西方语言)。是一套用于全文检索和搜寻的开源程式库,由 Apache 软件基金会支持和提供,使用的是一种称为倒排索引的结构,采用Lucene倒排索作为底层,这种结构适用于快速的全文搜索。
Lucene 提供了一个简单强大的接口,能够做全文索引和搜寻。然而 Lucene 非常复杂,想要使用它就需要深入了解检索的相关知识来理解它是如何工作的。
而 ES 使用 java 开发并使用 Lucene 作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的==RESTful API==来隐藏 Lucene 的复杂性,从而让全文搜索变得简单 。Elasticsearch 用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。
Elasticsearch 是面向文档,关系型数据库(Relational DB)和 Elasticsearch客观的对比!一切都是 json!
| Relational DB | Elasticsearch |
|---|---|
| 数据库(database) | 索引(indices) |
| 表(tables) | types |
| 行(rows) | documents |
| 字段(columns) | fields |
在 Elasticsearch(集群)中可以包含多个索引(数据库) ,每个索引中可以包含多个类型(表) ,每个类型下又包含多个文档(行),每个文档中又包含多个字段(列)。
Elasticsearch:9200
下载
-
进入Elasticsearch 官网,官网地址:www.elastic.co/cn/elastics…
-
点击下载
-
选择系统(以 Windows 为例)
-
等待下载完成
-
下载完成
安装
-
将下载的压缩包进行解压,解压之后即可使用。
-
目录结构
-
bin:启动文件
-
config:配置文件
- log4j2.properties:日志配置文件
- jvm.options:java 虚拟机相关的配置
- elasticsearch.yml:Elasticsearch 的配置文件;默认 9200 端口!跨域。
-
jdk:环境
-
lib:相关 JAR 包
-
logs:日志
-
modules:功能模块
-
plugins:插件
-
启动
-
双击 bin 目录下的 elasticsearch.bat 文件。
-
等待启动完成
默认通信地址:127.0.0.1:9300
默认公开地址:127.0.0.1:9200
-
浏览器访问 127.0.0.1:9200
name:主机名字。
cluster_name:集群名字,默认为 elasticsearch。
cluster_uuid:集群 uuid。
version:版本。、
tagline:你知道的,为了搜索。
ES Head:9100
可查看 Elasticsearch 中的信息插件。
注:需要安装 node.js 环境
安装
-
Github 下载地址:github.com/mobz/elasti…
-
解压 elasticsearch-head-master.zip 压缩包
-
进入 cmd,运行命令
已经下载的不用再执行第一条命令。
git clone git://github.com/mobz/elasticsearch-head.git cd elasticsearch-head npm install
启动
-
cmd 中启动 elasticsearch-head
运行以下命令。
npm run start -
在 elasticsearch.yml 中配置跨域
http.cors.enabled: true http.cors.allow-origin: "*" -
访问 http://localhost:9100/,点击连接,即可显示节点信息。
Kibana:5601
Elasticsearch 的可视化平台,需要先启动 Elasticsearch。
下载
-
Kibana 官网下载地址:www.elastic.co/cn/kibana/
-
点击下载 Kibana
-
选中对应版本下载即可
-
等待下载完成
-
下载完毕之后解压即可。解压非常慢。
启动
-
双击 bin 目录下的 Kibana.bat 文件
-
等待的时间有可能需要几分钟,根据电脑配置而定。
-
浏览器访问 http://localhost:5601/
汉化
-
config 目录下的 kibana.yaml 文件
-
重新启动 Kibana,访问 http://localhost:5601/
IK 分词器插件
IK 分词器可以对中文进行一个分词操作的插件。即把一段中文或者别的划分成一个个的关键字,在搜索的时候会将搜索关键词进行分词,会把数据库中或者索引库中的数据进行分词,然后进行一个匹配操作,默认的中文分词是将每个字看成一个词(不使用用IK分词器的情况下)。
IK 分词器默认提供了两个分词算法:(ik_smart 和 ik_max_word),其中 ik_smart 为最少切分,ik_max_word 为最细粒度划分!
下载
-
下载:Github 下载地址:github.com/medcl/elast…
要下载和 Elasticsearch 一样的版本。
-
下载完毕之后,放入到 Elasticsearch 的 plugins 目录下即可。
-
重启 Elasticsearch,可以看到 ik 插件被加载。
-
在 Kibana 中进行测试
GET _analyze { "analyzer": "ik_smart", "text": "蜘蛛侠" } GET _analyze { "analyzer": "ik_max_word", "text": "蜘蛛侠" }
自定义词典
在 IK 的 config 的目录中创建自定义文件 my.dic
添加文本,保存退出。
在 IKAnalyzer.cfg.xml 中配置自己的扩展字典。
重启 ES,
访问 Kibana 可以查看 “蜘蛛侠” 被分为一个词。
如果我们需要自定义分词即在 dic 文件中进行配置即可。
Rest 风格说明
Rest 风格是一种软件架构风格,不是一种标准,它只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
字段数据类型
主要字段类型如下:
-
字符串类型:text、keyword
- text:支持分词,全文检索,支持模糊、精确查询,不支持聚合,排序操作;text类型的最大支持的字符长度无限制,适合大字段存储;
- keyword:不进行分词,直接索引、支持模糊、支持精确匹配,支持聚合、排序操作。keyword类型的最大支持的长度为——32766个 UTF-8 类型的字符,可以通过设置 ignore_above 指定自持字符长度,超过给定长度后的数据将不被索引,无法通过 term 精确匹配检索返回结果。
-
数值型:long、Integer、short、byte、double、float、half float、scaled float
-
日期类型:date
-
布尔类型:boolean
-
二进制类型:binary
注:如果自己的文档字段没有指定,那么es就会给我们默认配置字段类型!
基本命令
| 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/索引名称/类型名称/文档id/_search | 查询所有数据 |
样例:创建索引
PUT /索引名/~类型名~/文档id
{请求体}
PUT /test1/type1/1
{
"name": "蜘蛛侠",
"age": 21
}
即创建一个索引 test1 ,文档类型名为 type1,文档 id 为 1。
通过 ES Head 查看数据
高亮显示
GET test/user/_search
{
"query": { //搜索匹配 name 包含"侠"
"match": {
"name": "侠"
}
},
"highlight": { //高亮
"pre_tags": "<font color='red'>", //html 前缀
"post_tags": "</font>", //html 后缀
"fields": { //属性
"name": {}
}
}
}
集成 SpringBoot
官方文档
-
点击链接进入官网:www.elastic.co/cn/,点击学习下面的…
-
找到并点击 Elasticsearch Clients
-
这里就是官方支持的文档了
测试 API
创建项目和 ES 配置类
-
新建 一个SpringBoot 项目,导入 Elasticsearch 和 fastjson 依赖。
-
编写 ElasticSearchClientConfig 配置类。
@Configuration public class ElasticSearchClientConfig { //RestHighLevelClient对象 @Bean public RestHighLevelClient restHighLevelClient(){ RestHighLevelClient client = new RestHighLevelClient( RestClient.builder( //集群设置多个 new HttpHost("127.0.0.1", 9200, "http"))); return client; } } -
测试类中注入 RestHighLevelClient 对象。
@Autowired
@Qualifier("restHighLevelClient")
private RestHighLevelClient client;
创建索引
//创建索引
@Test
void createIndex() throws IOException {
CreateIndexRequest request = new CreateIndexRequest("spring_test");
CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);
System.out.println(createIndexResponse);
}
判断索引是否存在
//判断索引是否存在,存在返回 true,不存在 false
@Test
void isExistIndex() throws IOException {
GetIndexRequest request = new GetIndexRequest("spring_test");
boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
System.out.println(exists);
}
删除索引
//删除索引,删除成功,response.isAcknowledged()=true,否则为 false
@Test
void deleteIndex() throws IOException {
DeleteIndexRequest request = new DeleteIndexRequest("spring_test");
AcknowledgedResponse response = client.indices().delete(request, RequestOptions.DEFAULT);
System.out.println(response.isAcknowledged());
}
添加文档
//测试添加文档(User 对象)
@Test
void addDoc() throws IOException {
//创建对象
User user = new User("Jie", 20);
//创建请求
IndexRequest request = new IndexRequest("spring_test");
//创建规则
request.id("1");
request.timeout(TimeValue.timeValueSeconds(1));
//将数据 json 格式放入请求
request.source(JSON.toJSONString(user), XContentType.JSON);
//客户端发送请求,获取响应的结果
IndexResponse response = client.index(request, RequestOptions.DEFAULT);
System.out.println(response);
System.out.println(response.status());
}
判断文档是否存在
//判断文档是否存在 get /index/doc/1
@Test
void isExistsDoc() throws IOException {
//获取 GetRequest 请求,构造重载 index,type,id
GetRequest request = new GetRequest("spring_test","1");
//不获取返回的 _source 的上下文
request.fetchSourceContext(new FetchSourceContext(false));
request.storedFields("_none_");
boolean exists = client.exists(request, RequestOptions.DEFAULT);
System.out.println(exists);
}
获取文档信息
@Test
void getDoc() throws IOException {
//获取 GetRequest 请求,构造重载 index,type,id
GetRequest request = new GetRequest("spring_test","1");
GetResponse response = client.get(request, RequestOptions.DEFAULT);
//将文档内容作为字符串输出
System.out.println(response.getSourceAsString());
//响应信息是与命令是一样的
System.out.println(response);
}
更新文档信息
- 获取 UpdateRequest 请求
- 设置数据,将数据转为 JSON 格式。
- 客户端执行请求
//更新文档信息
@Test
void updateDoc() throws IOException {
//获取 GetRequest 请求,构造重载 index,type,id
UpdateRequest request = new UpdateRequest("spring_test","1");
request.timeout("1s");
//创建对象
User user = new User("I'm Jie", 22);
//将对象封装为 JSON 类型
request.doc(JSON.toJSONString(user),XContentType.JSON);
UpdateResponse response = client.update(request, RequestOptions.DEFAULT);
System.out.println(response);
System.out.println(response.status());
}
删除文档信息
- 获取 DeleteRequest 请求
- 客户端执行请求
//删除文档信息
@Test
void delDoc() throws IOException {
//获取 GetRequest 请求,构造重载 index,type,id
DeleteRequest request = new DeleteRequest("spring_test","1");
request.timeout("1s");
DeleteResponse response = client.delete(request, RequestOptions.DEFAULT);
System.out.println(response);
System.out.println(response.status());
}
批量添加文档信息
- 获取 BulkRequest 请求
- 准备数据
- 批处理请求
- 循环添加请求数据,将数据转为 JSON 格式。
- 客户端执行请求
//批量添加文档信息
@Test
void bulkRequest() throws IOException {
BulkRequest request = new BulkRequest();
request.timeout("10s");
//准备数据
ArrayList<User> users = new ArrayList<>();
users.add(new User("test1",2));
users.add(new User("test2",3));
users.add(new User("test3",2));
users.add(new User("test4",5));
users.add(new User("test5",2));
//批处理请求
for (int i = 0; i < users.size(); i++) {
request.add(
new IndexRequest("spring_test")
.id((i+1)+"") //不设置 id,默认随机 id
.source(JSON.toJSONString(users.get(i)),XContentType.JSON));
}
//提交请求
BulkResponse response = client.bulk(request, RequestOptions.DEFAULT);
System.out.println(response);
System.out.println(response.status());
}
查询信息
- 获取 SearchRequest 请求
- 构建搜索条件
- 设置查询条件(通过 SearchSourceBuilder 构造对应的条件)
- 客户端执行请求
- 解析响应结果
//查询
//SearchRequest 搜索请求
//SearchSourceBuilder 条件构造
//使用 QueryBuilders 创造条件
//HighlightBuilder 构建高亮
//TermQueryBuilder 精确查询
//MatchAllQueryBuilder 匹配所有
@Test
void search() throws IOException {
//请求
SearchRequest search = new SearchRequest("spring_test");
//构建搜索条件
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
/*查询条件,可以使用 QueryBuilders 工具类实现*/
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("age", 2);
sourceBuilder.query(termQueryBuilder);
//设置时间
sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
search.source(sourceBuilder);
SearchResponse response = client.search(search, RequestOptions.DEFAULT);
System.out.println(response);
System.out.println(JSON.toJSONString(response.getHits()));
System.out.println("===============================");
for (SearchHit hit : response.getHits().getHits()) {
System.out.println(hit.getSourceAsMap());
}
}
高亮字段
- 获取 SearchRequest 请求
- 设置搜索条件
- 设置查询条件
- 设置高亮
- 执行查询
- 客户端执行请求
- 解析查询结果
- 将高亮字段替换掉原来的字段(查询出来的高亮字段和源字段不是同一个,所以需要用高亮后的字段替换源字段)
//高亮字段
@Test
void highLight() throws IOException {
//请求
SearchRequest search = new SearchRequest("spring_test");
//构建搜索条件
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", "test1");
sourceBuilder.query(termQueryBuilder);
sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
//高亮
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("name"); //设置高亮字段
highlightBuilder.requireFieldMatch(false); //取消多个高亮
highlightBuilder.preTags("<font color='red'>"); //前缀
highlightBuilder.postTags("</font>"); //后缀
sourceBuilder.highlighter(highlightBuilder);
//执行搜索
search.source(sourceBuilder);
SearchResponse response = client.search(search, RequestOptions.DEFAULT);
//解析结果
ArrayList<Map<String,Object>> list = new ArrayList<>();
for (SearchHit hit : response.getHits().getHits()) {
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
HighlightField name = highlightFields.get("name");
//获取原理的结果
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
// 将高亮字段替换掉原来的字段
if(name!=null){
Text[] texts = name.getFragments();
String n_name="";
for (Text text : texts) {
n_name += text;
}
sourceAsMap.put("name",n_name);
}
list.add(sourceAsMap);
}
}