一. Elastic Search简介
Elasticsearch 是一个分布式、RESTful 风格,基于Lucene封装和增强,的搜索和数据分析引擎,能够解决不断涌现出的各种用例。它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单。
功能:
- 全文搜索
- 结构化搜索
- 分析
Elastic Search与solr对比:
- 当单纯对已有数据搜索,solr更快,常用于电商等查询多的应用
- 当实时建立索引时,solr会产生io阻塞,查询性能会比较差,es无明显变化,常用于实时搜索
- 随数据量增加,solr的搜索效率会大幅下降,es无明显变化
- solr使用zookeeper进行分布式管理,es自带分布式协调管理
- solr支持多种格式,es只支持json
- solr具有很多功能,es更注重核心功能,支持插件扩展
- solr社区更加完善,es开发维护者少、更新快、学习成本高
作为搜索引擎,es比solr效率高50倍左右。
ELK:由ElasticSearch、Logstash和Kiabana三个开源工具组成,常用作开源实时日志分析平台。
建议使用kibana去调试开发es,非常好用,还提供了中文的界面;同时可以配合使用谷歌的插件或者安装es header。下面都是使用这两个工具进行演示。
二. 核心概念
2.1. 设计
es可以类似为文档型数据库,一切都是json。
逻辑设计:索引 > 类型 > 文档ID
物理设计:将每个索引划分成多个分片,每个分片可以在集群中的不同服务器间迁移。
一个集群至少有一个节点,一个节点就是一个es进程,节点可以有多个索引,如果创建索引,那么索引将会由5个(默认)主分片构成,每一个主分片有一个副本。一个分片就是一个Lucene索引,一个包含倒排索引的文件目录。倒排索引使得es在不扫描全部文档的情况下,搜索到包含关键字的文档。
2.2 倒排索引
正排索引指的是:key为文档1,value为文档中的词;
倒排索引指的是:key为某个词,value为包含该词的文档;
采用Lucene倒排索引作为底层,有利于全文搜索。
步骤1:将每个文档拆分成独立的词,然后创建一个包含所有不重复词条的排序列表,列出每个词条是否出现在某个文档中。
当搜索某个字符串,比如 to forever ,通过上面的表,我们可以得知,doc_1匹配2个词,doc_2匹配1个词,我们将匹配的词数称为权重(score),它会按照权重的大小由高到低返回结果。
2.3 类型
如果不设置,系统会自己猜。已经被废弃使用了。
建议全部不写类型,下面示列中有些写了类型的,请无视。
默认类型为_doc
https://blog.youkuaiyun.com/qq_29860591/article/details/109340346
https://blog.youkuaiyun.com/numbbe/article/details/109656567
补充. IK分词器插件
下载地址:https://github.com/medcl/elasticsearch-analysis-ik/releases/tag/v7.14.0
算法:最少切分ik_smart;最细粒度切分ik_max_word
可以自己扩展词典,新建dic文件,每写一个词换一行,然后在下方的xml中注入。
三. 基础操作
官方教程:https://www.elastic.co/guide/cn/elasticsearch/guide/current/index.html
官方教程版本过于落后,只能参考看看。
官方文档:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high.html
版本可以选择,但是全是英语QAQ
3.1. 创建索引以及字段
PUT /索引名
类型属性创建完就无法更改
java api: https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high-document-index.html
使用IndexRequest:
public boolean createIndex(String index, String id, Map<String, Object> parameters) throws IOException {
IndexRequest indexRequest = new IndexRequest(index).id(id).source(parameters);
IndexResponse indexResponse = client.index(indexRequest, RequestOptions.DEFAULT);
return indexResponse.getResult() == DocWriteResponse.Result.CREATED;
}
测试代码:
@Test
void contextLoads() throws IOException {
Map<String, Object> map= new HashMap();
contentService.createIndex("create", "1", map);
}
3.2. 添加数据
没有索引的话,自动创建索引】
PUT /索引名/类型名 /文档id
{请求体}
因为es7已经废弃type,es8以后会删除type,所以这边建议不使用它。
默认用_doc的来创建索引,它会非常智能地选择匹配的类型。
3.3. 获取数据
GET 索引名
GET _cat/ 可以获得索引情况
GET _cat/health
GET _cat/indices
java源码注释:
根据 id 从索引中获取文档(其源)的请求。 最好使用org.elasticsearch.client.Requests.getRequest(String)创建。
该操作需要设置index() 、 type(String)和id(String) 。
请参见:
GetResponse , org.elasticsearch.client.Requests.getRequest(String) , org.elasticsearch.client.Client.get(GetRequest)
一般通过GetRequest(String index, String id)来获取文档【type类型已经过时了】。
3.4. 修改索引
修改完成后,版本号会自增1【CAS乐观锁】,状态修改为updated;
- 直接put同文件id覆盖
- post + update
第二种可以部分更新,是新版本推荐的方法
3.5 删除操作
DELETE 索引名
DELETE 索引名/类型 /文档id
四. 文档操作(重点)
4.1. 条件查询
GET 索引名/类型 /_search?q=属性名:属性值
public Map<String, Object> getIndex(String index, String id) throws IOException{
GetRequest getRequest = new GetRequest(index, id);
GetResponse getResponse = client.get(getRequest, RequestOptions.DEFAULT);
if(getResponse.isExists()) {
return getResponse.getSourceAsMap();
}
return null;
}
@Test
void getContent() throws IOException {
Map<String, Object> map = contentService.getIndex("hzh", "1");
if(map == null) {
return;
}
for (Map.Entry<String, Object> entry : map.entrySet()) {
System.out.println(entry.getKey() + " " + entry.getValue());
}
}
模糊查找
score为匹配度
缩写写法:
(这里请不要加user这些类型)
通过_source可以指定需要的信息:
这里选择获取name,不过滤属性。include是获取的属性,exclude是过滤的属性,第一个参数必须为true。
public Map<String, Object> getSource(String index, String id) throws IOException {
GetSourceRequest getSourceRequest = new GetSourceRequest(index, id);
String[] includes = new String[]{
"name"};
String[] excludes = Strings.EMPTY_ARRAY;
getSourceRequest.fetchSourceContext(new FetchSourceContext(true, includes, excludes));
GetSourceResponse getSourceResponse = client.getSource(getSourceRequest, RequestOptions.DEFAULT);
return getSourceResponse.getSource();
}
通过sort可以排序,asc为升序,desc为降序
分页
from 和 size
从第from个数据开始【从零开始】,返回size条数据
must / should / must_not
等同于and / or / !(and)
但需要注意的是,中文匹配,只要其中一个字匹配上了,就算匹配成功。
精确匹配 term/terms ;模糊匹配 match/matches 会调用分词器【keyword类型仍然不会被分词】
中文匹配还是很诡异,只能匹配字符串中的任意一个字,你多输一个字就出不来。
因为当我们用 term 查询查找精确值的时候,它并不在我们的倒排索引中,中文实际上已经被分词了。当我们将这个中文的类型定义为keyword的时候,我们就可以获取到它的值。
filiter过滤器,放在bool下;
range:可以指定范围 lt<,lte ≤,gt>,gte≥
高亮查询
自定义高亮:设置前缀和后缀
五. 集成SpringBoot
5.1. 配置环境
- springboot导入es模块
- 配置类
package com.hzh.es.config;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ElasticSearchConfig {
@Bean
public RestHighLevelClient restHighLevelClient() {
return new RestHighLevelClient(
RestClient.builder(
new HttpHost("localhost", 9200, "http")));
}
}
如果你很不幸地和我一样,手贱地配置了账号密码,那么还得加亿点代码
package com.hzh.es.config;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org