typora-copy-images-to: images
ElasticSearch
文章目录
1、ElasticSearch 安装及可视化(Windows)
安装:ElasticSearch、head可视化、Kibana、IK
-
1、下载 es: https://www.elastic.co/cn/downloads/elasticsearch
-
2、启动 es:bin 目录下的 elasticsearch.bat 文件
-
3、下载安装可视化界面 ElasticSearch head插件: https://github.com/mobz/elasticsearch-head
-
4、启动 head 插件:进入 head 目录进入 cmd 命令:
npm install (快点的话用 cnpm install,此步骤只在安装时使用,已安装则不必运行)
npm run start (启动)
在浏览器中打开: http://localhost:9100/ -
5、连接测试发现,存在跨域问题:配置 es 中的 yml 文件后面加上
http.cors.enabled: true
http.cors.allow-origin: “*” -
6、重启 es
-
7、下载 Kibana (版本与 es 对应): https://www.elastic.co/cn/downloads/kibana
-
8、启动 Kibana:bin 目录下的 kibana.bat 文件,并在浏览器上访问:http://localhost:5601
-
9、将 Kibana 界面汉化(选择性修改):在 config 目录下 kibana.yml 文件后面加上
i18n.locale: “zh-CN”
-
10、重启 Kibana
-
11、下载 IK (版本跟 es 对应): https://github.com/medcl/elasticsearch-analysis-ik **
-
12、将 IK 放入到 es 文件下的 plugins 目录下的 IK 文件夹中(IK 文件夹自己创建)
-
13、重启 es,head 插件,Kibana
2、启动 ElasticSearch
- 运行安装步骤中的:2、4、8 步
3、IK 分词器
ik_smart
-
最小切分
-
将“非常喜欢樊召康”最小切分
发送请求:
GET _analyze
{
“analyzer”: “ik_smart”,
“text”: “非常喜欢樊召康”
}返回json数据
{ "tokens" : [ { "token" : "非常", "start_offset" : 0, "end_offset" : 2, "type" : "CN_WORD", "position" : 0 }, { "token" : "喜欢", "start_offset" : 2, "end_offset" : 4, "type" : "CN_WORD", "position" : 1 }, { "token" : "樊", "start_offset" : 4, "end_offset" : 5, "type" : "CN_CHAR", "position" : 2 }, { "token" : "召", "start_offset" : 5, "end_offset" : 6, "type" : "CN_CHAR", "position" : 3 }, { "token" : "康", "start_offset" : 6, "end_offset" : 7, "type" : "CN_CHAR", "position" : 4 } ] }
ik_max_word
-
最细粒度划分
-
将“非常喜欢樊召康”最细粒度划分
发送请求:
GET _analyze
{
“analyzer”: “ik_max_word”,
“text”: “非常喜欢樊召康”
}返回json数据:
{ "tokens" : [ { "token" : "非常", "start_offset" : 0, "end_offset" : 2, "type" : "CN_WORD", "position" : 0 }, { "token" : "喜欢", "start_offset" : 2, "end_offset" : 4, "type" : "CN_WORD", "position" : 1 }, { "token" : "樊", "start_offset" : 4, "end_offset" : 5, "type" : "CN_CHAR", "position" : 2 }, { "token" : "召", "start_offset" : 5, "end_offset" : 6, "type" : "CN_CHAR", "position" : 3 }, { "token" : "康", "start_offset" : 6, "end_offset" : 7, "type" : "CN_CHAR", "position" : 4 } ] }
添加分词器
-
发现问题:上面的“樊召康”被拆分了,不希望被拆分
-
解决问题:自己需要的词,需要自己添加到我们的分词器的字典中
-
步骤(两步)
-
第一步:在 IK 文件下的 config 目录下创建 .dic 文件
- 例如:创建 fzk.dic 文件,内容为 樊召康
-
第二步:重启 ElasticSearch、Kibana
-
第三步:在 Kibana 网址中进行请求
发送请求:
GET _analyze
{
“analyzer”: “ik_smart”,
“text”: “非常喜欢樊召康”
}返回json数据:樊召康未被拆分
{ "tokens" : [ { "token" : "非常", "start_offset" : 0, "end_offset" : 2, "type" : "CN_WORD", "position" : 0 }, { "token" : "喜欢", "start_offset" : 2, "end_offset" : 4, "type" : "CN_WORD", "position" : 1 }, { "token" : "樊召康", "start_offset" : 4, "end_offset" : 7, "type" : "CN_WORD", "position" : 2 } ] }
-
4、简单语句使用
增加(PUT)
PUT /fzk/type/1
{
"name": "樊召康123",
"age": 20
}
//PUT: 请求头
//fzk: 索引名称
//type: 类型名称
//1: 特定的ID
//{}: json数据,存储的信息
修改(POST)
POST /fzk/type/1/_update
{
"doc": {
"name": "fzk"
}
}
//POST: 请求头
//fzk: 索引名称
//type: 类型名称
//1: 修改的这个ID的数据
//{}: json数据,存储的信息,修改 “name” 为 “fzk”
删除(DELETE)
DELETE /fzk
//DELETE: 请求头
//fzk: 索引名称
//删除索引为 “fzk”
查询(GET)
初始数据
{
"_index" : "index1",
"_type" : "type1",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"name" : "樊召康123",
"age" : 20
}
},
{
"_index" : "index1",
"_type" : "type1",
"_id" : "2",
"_score" : 1.0,
"_source" : {
"name" : "222",
"age" : 10
}
},
{
"_index" : "index1",
"_type" : "type1",
"_id" : "4",
"_score" : 1.0,
"_source" : {
"name" : "樊召康1739084",
"age" : 15
}
},
{
"_index" : "index1",
"_type" : "type1",
"_id" : "3",
"_score" : 1.0,
"_source" : {
"name" : "1732047190樊召康1739084",
"age" : 40
}
}
简单查询
- _source:输出特定的字段数据
- sort:排序
- from-size:分页
GET /index1/type1/_search
{
"query": {
"match": {
"name": "樊召康"
}
}
}
//GET: 请求头
//index1: 索引名称
//type1: 类型名称
//_search: 所有数据
//{}: json数据,查询条件
//query: 查询
//match: 相似匹配,查询 “name” 中含有 “樊召康” 的所有数据,相当于SQL中的:like %樊召康%
GET /index1/type1/_search
{
"query": {
"match": {
"name": "樊召康"
}
},
"_source": ["name"]
}
//_source: 输出只有 “name” 字段的数据,相当于SQL中的:select name
GET /index1/type1/_search
{
"query": {
"match": {
"name": "樊召康"
}
},
"sort": [
{
"age": {
"order": "desc"
}
}
]
}
//sort: 排序,按照 “age” 字段进行降序,相当于SQL中的:order by age desc
GET /index1/type1/_search
{
"query": {
"match": {
"name": "樊召康"
}
},
"from": 0,
"size": 10
}
//from: 第 0 条数据开始
//size: 第 0+10 条数据结束
//相当于MySQL中的:limit m, n
复杂查询(bool查询)
- must:与(&&)
- must_not:非(!)
- should:或(||)
- filter:过滤器
GET /index1/type1/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"name": "樊召康"
}
},
{
"match": {
"age": 20
}
}
]
}
}
}
//must: 与 条件(&&),相当于SQL中的:and
//查询 “name” 字段中含有 “樊召康” 且 “age” 为 20 的所有数据
GET /index1/type1/_search
{
"query": {
"bool": {
"must_not": [
{
"match": {
"name": "樊召康"
}
}
]
}
}
}
//must_not: 非(!),相当于SQL中的:not
//查询 “name” 字段中不含有 “樊召康” 的所有数据
GET /index1/type1/_search
{
"query": {
"bool": {
"should": [
{
"match": {
"name": "樊召康"
}
},
{
"match": {
"age": 20
}
}
]
}
}
}
//should: 或(||),相当于SQL中的:or
//查询 “name” 字段中含有 “樊召康” 或 “age” 为 20 的所有数据
GET /index1/type1/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"name": "樊召康"
}
}
],
"filter": {
"range": {
"age": {
"gte": 10,
"lte": 20
}
}
}
}
}
}
//filter: 过滤器
//range: 返回匹配,相当于SQL中的:>, >=, <, <=
//>:gt, >=:gte, <:lt, <=:lte
//查询 “name” 字段中含有 “樊召康” 且 “age” 为 10<=age<=20 的所有数据
匹配多个条件
GET /index1/type1/_search
{
"query": {
"match": {
"name": "樊 康"
}
}
}
//在一个字段中查询多个条件,只需用 “空格” 将条件隔开,es 会根据权重来进行排序
//例如上面的: "name": "樊 康" , 查询 “name” 中包含 “樊”,“康” 的数据根据权重进行排序
精确查询
- term:直接根据倒排索引指定的词条进行精确的查找
GET /index1/type1/_search
{
"query": {
"term": {
"name": "樊召康123"
}
}
}
//term: 精确匹配,相当于SQL中的:=
//查询 “name” 大于 “樊召康123” 的所有数据
高亮查询
- highlight:高亮
GET /index1/type1/_search
{
"query": {
"match": {
"name": "樊召康"
}
},
"highlight": {
"fields": {
"name": {}
}
}
}
//highlight: 高亮
//fields: 高亮的数据,"name": {} 代表:将查到的 “樊召康” 三个字高亮
//返回值高亮的部分:"<em>樊</em><em>召</em><em>康</em>123"
GET /index1/type1/_search
{
"query": {
"match": {
"name": "樊召康"
}
},
"highlight": {
"pre_tags": "<p style='color:red'>",
"post_tags": "</p>",
"fields": {
"name": {}
}
}
}
//自定义高亮的属性
//pre_tags: 前缀标签
//post_tags: 后缀标签
//返回值高亮的部分:"<p style='color:red'>樊</p><p style='color:red'>召</p><p style='color:red'>康</p>123"
5、集成 SpringBoot
https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.6/java-rest-high.html
环境搭建(两步)
-
第一步:创建SpringBoot工程,并在 pom.xml 文件中引入依赖
特别注意:引入的包的版本要与安装的 es 版本相同(我安装的是 7.6.1,以7.6.1为例)
<!-- 将修改版本 --> <properties> <java.version>1.8</java.version> <elasticsearch.version>7.6.1</elasticsearch.version> </properties> <!-- 引入依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency>
-
第二步:编写配置文件
@Configuration public class ElasticSearchClientConfig { /** * 单机配置 */ @Bean public RestHighLevelClient restHighLevelClient() { RestHighLevelClient client = new RestHighLevelClient( RestClient.builder( new HttpHost("localhost", 9200, "http"))); return client; } /** * 集群配置 */ /* @Bean public RestHighLevelClient restHighLevelClient() { RestHighLevelClient client = new RestHighLevelClient( RestClient.builder( //集群配置 new HttpHost("localhost", 9200, "http"), new HttpHost("localhost", 9201, "http"))); return client; } */ }
索引 API 的简单使用
-
创建索引、判断索引是否存在、删除索引
@RunWith(SpringRunner.class) @SpringBootTest class SpringbootinitializrApplicationTests { @Autowired @Qualifier("restHighLevelClient") private RestHighLevelClient client; /** * 创建索引 * 参考地址:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.6/java-rest-high-create-index.html */ @Test public void createIndex() throws IOException { //创建索引请求 CreateIndexRequest request = new CreateIndexRequest("fzk"); //创建索引 CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT); System.out.println(response); } /** * 索引是否存在 * 参考地址:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.6/java-rest-high-indices-exists.html */ @Test public void isIndexExists() throws IOException { //创建获取索引请求 GetIndexRequest request = new GetIndexRequest("fzk"); //判断是否存在索引 boolean exists = client.indices().exists(request, RequestOptions.DEFAULT); System.out.println(exists); } /** * 删除索引 * 参考地址:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.6/java-rest-high-delete-index.html */ @Test public void deleteIndex() throws IOException { //获取删除索引请求 DeleteIndexRequest request = new DeleteIndexRequest("fzk"); //删除索引 AcknowledgedResponse delete = client.indices().delete(request, RequestOptions.DEFAULT); System.out.println(delete.isAcknowledged()); } }
文档 API 的简单使用
-
实体类
@Data @AllArgsConstructor @NoArgsConstructor public class Person { private String name; private int age; }
-
增删改查文档
@RunWith(SpringRunner.class) @SpringBootTest class SpringbootinitializrApplicationTests { @Autowired @Qualifier("restHighLevelClient") private RestHighLevelClient client; /** * 给索引添加数据 * 参考地址:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.6/java-rest-high-document-index.html */ @Test public void addData() throws IOException { //创建对象 Person person = new Person("樊召", 10); //创建索引请求 IndexRequest request = new IndexRequest("fzk"); //设置索引特定的 id 值 request.id("1"); //设置内容 request.source(JSON.toJSONString(person), XContentType.JSON); //超时时间 request.timeout("1s"); //请求-响应 IndexResponse response = client.index(request, RequestOptions.DEFAULT); System.out.println(response.toString()); System.out.println(response.status()); } /** * 判断文档是否存在 * 参考地址:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.6/java-rest-high-document-exists.html */ @Test public void isDataExists() throws IOException { //创建索引请求 GetRequest getRequest = new GetRequest("fzk", "1"); //不获取 _source 中的数据 getRequest.fetchSourceContext(new FetchSourceContext(false)); getRequest.storedFields("_none_"); //判断是否存在 boolean exists = client.exists(getRequest, RequestOptions.DEFAULT); System.out.println(exists); } /** * 获取文档内容 * 参考地址:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.6/java-rest-high-document-get.html */ @Test public void getData() throws IOException { GetRequest getRequest = new GetRequest("fzk", "1"); //获取文档内容 GetResponse getResponse = client.get(getRequest, RequestOptions.DEFAULT); System.out.println(getResponse.getSource()); System.out.println(getResponse); } /** * 修改文档内容 * 参考地址:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.6/java-rest-high-document-update.html */ @Test public void update() throws IOException { UpdateRequest request = new UpdateRequest("fzk", "1"); Person person = new Person("fzk", 20); request.doc(JSON.toJSONString(person), XContentType.JSON); UpdateResponse update = client.update(request, RequestOptions.DEFAULT); System.out.println(update.status()); } /** * 删除文档内容 * 参考地址:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.6/java-rest-high-document-delete.html */ @Test public void delete() throws IOException { DeleteRequest request = new DeleteRequest("fzk", "1"); DeleteResponse delete = client.delete(request, RequestOptions.DEFAULT); System.out.println(delete.status()); } /** * 批量添加内容 * 参考地址:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.6/java-rest-high-document-bulk.html */ @Test public void bulkAdd() throws IOException { List<Person> personList = new ArrayList<>(); personList.add(new Person("fzk1", 1)); personList.add(new Person("fzk2", 2)); personList.add(new Person("fzk3", 3)); personList.add(new Person("fzk4", 4)); personList.add(new Person("fzk5", 5)); personList.add(new Person("fzk6", 6)); personList.add(new Person("fzk7", 7)); personList.add(new Person("fzk8", 8)); BulkRequest bulkRequest = new BulkRequest(); for (int i = 0; i < personList.size(); i++) { bulkRequest.add(new IndexRequest("fzk") .id("" + (i + 1)) .source(JSON.toJSONString(personList.get(i)), XContentType.JSON)); } //批量处理 BulkResponse bulk = client.bulk(bulkRequest, RequestOptions.DEFAULT); System.out.println(bulk.status()); } }
查询 API 的简单使用
-
查询条件:
- QueryBuilders.xxxQuery():常用的
- matchAllQuery() :查询所有
- matchQuery(String name, Object text) :按条件查询
- multiMatchQuery(Object text, String… fieldNames) : 查询多个条件
- matchPhraseQuery(String name, Object text)
- termQuery(String name, Object value) :精确查询
- rangeQuery(String name) :范围查询
- existsQuery(String name) : 是否存在查询
- boolQuery() :布尔查询
- must(QueryBuilder queryBuilder) :与 查询(&&)
- mustNot(QueryBuilder queryBuilder) : 非 查询(!)
- should(QueryBuilder queryBuilder) :或 查询(||)
- filter(QueryBuilder queryBuilder) :过滤器查询
@RunWith(SpringRunner.class) @SpringBootTest class SpringbootinitializrApplicationTests { @Autowired @Qualifier("restHighLevelClient") private RestHighLevelClient client; @Test public void query() throws IOException { //1、创建搜索请求 SearchRequest searchRequest = new SearchRequest("fzk"); //2、创建条件查询 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); //3、编写查询条件,QueryBuilders.xxxQuery() 的都是查询,查询思路和请求的命令行一样 //单个条件查询 MatchQueryBuilder query = QueryBuilders.matchQuery("name", "fzk1"); //多个条件查询 /* BoolQueryBuilder query = QueryBuilders.boolQuery(); query.must(QueryBuilders.matchQuery("name", "fzk1")); query.must(QueryBuilders.matchQuery("age", "1")); */ //4、将查询条件添加到 SearchSourceBuilder 中,并添加其他条件 searchSourceBuilder.query(query); //分页 searchSourceBuilder.from(0); //从 0 开始 searchSourceBuilder.size(2); //到 0+2 结束 //高亮 HighlightBuilder highlightBuilder = new HighlightBuilder(); //创建高亮 highlightBuilder.field("name"); //高亮的 “name” 字段 highlightBuilder.requireFieldMatch(false); //多个高亮显示 highlightBuilder.preTags("<p style='color:red'>"); //前缀标签 highlightBuilder.postTags("</p>"); //后缀标签 searchSourceBuilder.highlighter(highlightBuilder); //将 HighlightBuilder 加入到 SearchSourceBuilder //5、将 SearchSourceBuilder 添加到 SearchRequest 中 searchRequest.source(searchSourceBuilder); //6、查询请求响应 SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); //7、打印查询到的数据 for (SearchHit hit : searchResponse.getHits().getHits()) { System.out.println(hit.getSourceAsMap()); //打印查询到的信息 HighlightField highlightField = hit.getHighlightFields().get("name"); //高亮信息 if(highlightField != null){ System.out.println(highlightField.fragments()[0]); //打印高亮的数据 } System.out.println("=================="); } } }
- QueryBuilders.xxxQuery():常用的