Spring Boot整合ElasticSearch
1 客户端
ES提供多种不同的客户端:
1.1 TransportClient
ES提供的传统客户端,官方计划8.0版本删除此客户端。
1.2 RestClient
RestClient是官方推荐使用的,它包括两种:REST Low Level Client和 REST High Level Client。ES在6.0之后提供REST High Level Client, 两种客户operator端官方更推荐使用 REST High Level Client,不过当前它还处于完善中,有些功能还没有。
2 搭建工程
2.1 配置文件
<!-- 修改elasticsearch的版本 -->
<properties>
<elasticsearch.version>6.2.3</elasticsearch.version>
</properties>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>${elasticsearch.version}</version>
</dependency>
2.2 application.yml
spring:
elasticsearch:
rest:
uris:
- http://192.168.23.17:9200 #自己的地址
2.3 App
package com.dome;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ElasticsearchApp {
public static void main(String[] args) {
SpringApplication.run(ElasticsearchApp.class, args);
}
}
3 写入操作
package com.dome.test;
import com.powernode.ElasticsearchApp;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.IndicesClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.io.IOException;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = ElasticsearchApp.class)
public class WriteTest {
@Autowired
private RestHighLevelClient restHighLevelClient;
/**
* 创建索引库并添加映射
*/
@Test
public void testCreateIndex() throws IOException {
//创建“创建索引请求”对象,并设置索引名称
CreateIndexRequest createIndexRequest = new CreateIndexRequest("test");
//设置索引参数
createIndexRequest.settings("{\n" +
" \"number_of_shards\": 2,\n" +
" \"number_of_replicas\": 0\n" +
" }", XContentType.JSON);
//设置映射
createIndexRequest.mapping("course", "{\n" +
" \"_source\": {\n" +
" \"excludes\":[\"description\"]\n" +
" }, \n" +
" \"properties\": {\n" +
" \"name\": {\n" +
" \"type\": \"text\",\n" +
" \"analyzer\": \"ik_max_word\",\n" +
" \"search_analyzer\": \"ik_smart\"\n" +
" },\n" +
" \"description\": {\n" +
" \"type\": \"text\",\n" +
" \"analyzer\": \"ik_max_word\",\n" +
" \"search_analyzer\": \"ik_smart\"\n" +
" },\n" +
" \"studymodel\": {\n" +
" \"type\": \"keyword\"\n" +
" },\n" +
" \"pic\":{\n" +
" \"type\": \"text\",\n" +
" \"index\": false\n" +
" },\n" +
" \"pice\":{\n" +
" \"type\": \"float\"\n" +
" }\n" +
" }\n" +
"}", XContentType.JSON);
//创建索引操作客户端
IndicesClient indices = restHighLevelClient.indices();
//创建响应对象
CreateIndexResponse createIndexResponse = indices.create(createIndexRequest);
//得到响应结果
boolean acknowledged = createIndexResponse.isAcknowledged();
System.out.println(acknowledged);
}
/**
* 添加文档
*
* @throws IOException
*/
@Test
public void testAddDocument() throws IOException {
IndexRequest indexRequest = new IndexRequest("test", "course", "1");
indexRequest.source("{\n" +
" \"name\":\"spring cloud实战\",\n" +
" \"description\":\"本课程主要从四个章节进行讲解: 1.微服务架构入门 2.spring cloud 基础入门 3.实战Spring Boot 4.注册中心eureka。\",\n" +
" \"studymodel\":\"201001\",\n" +
" \"price\":5.6\n" +
"}", XContentType.JSON);
//创建索引操作客户端
IndexResponse indexResponse = restHighLevelClient.index(indexRequest);
System.out.println(indexResponse.toString());
}
/**
* 批量添加文档
*
* @throws IOException
*/
@Test
public void testBulkAddDocument() throws IOException {
BulkRequest bulkRequest = new BulkRequest();
bulkRequest.add(new IndexRequest("test", "course","2").source("{\n" +
" \"name\": \"spring开发基础\",\n" +
" \"description\": \"spring 在java领域非常流行,java程序员都在用。\",\n" +
" \"studymodel\": \"201001\",\n" +
" \"price\":88.6,\n" +
" \"pic\":\"group1/M00/00/00/wKhlQFs6RCeAY0pHAAJx5ZjNDEM428.jpg\"\n" +
"}", XContentType.JSON));
bulkRequest.add(new IndexRequest("test", "course","3").source("{\n" +
" \"name\": \"java编程基础\",\n" +
" \"description\": \"java语言是世界第一编程语言,在软件开发领域使用人数最多。\",\n" +
" \"studymodel\": \"201001\",\n" +
" \"price\":68.6,\n" +
" \"pic\":\"group1/M00/00/00/wKhlQFs6RCeAY0pHAAJx5ZjNDEM428.jpg\"\n" +
"}", XContentType.JSON));
//创建索引操作客户端
BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest);
System.out.println(bulkResponse.toString());
}
/**
* 修改文档
*
* @throws IOException
*/
@Test
public void testUpdateDocument() throws IOException {
UpdateRequest updateRequest = new UpdateRequest("test", "course", "1");
updateRequest.doc("{\n" +
" \"price\":66.6\n" +
"}", XContentType.JSON);
//创建索引操作客户端
UpdateResponse updateResponse = restHighLevelClient.update(updateRequest);
System.out.println(updateResponse.toString());
}
/**
* 删除文档
*
* @throws IOException
*/
@Test
public void testDeleteDocument() throws IOException {
DeleteRequest deleteRequest = new DeleteRequest("test", "course", "1");
//创建索引操作客户端
DeleteResponse deleteResponsee = restHighLevelClient.delete(deleteRequest);
System.out.println(deleteResponsee.toString());
}
/**
* 删除索引库
*
* @throws IOException
*/
@Test
public void testDeleteIndex() throws IOException {
DeleteIndexRequest indexRequest = new DeleteIndexRequest("test");
//创建索引操作客户端
IndicesClient indices = restHighLevelClient.indices();
//创建响应对象
DeleteIndexResponse deleteIndexResponse = indices.delete(indexRequest);
//得到响应结果
boolean acknowledged = deleteIndexResponse.isAcknowledged();
System.out.println(acknowledged);
}
}
4 读取操作
package com.dome.test;
import com.powernode.ElasticsearchApp;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.io.IOException;
import java.util.Map;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = ElasticsearchApp.class)
public class ReadTest {
@Autowired
private RestHighLevelClient restHighLevelClient;
private SearchRequest searchRequest;
private SearchResponse searchResponse;
private SearchHits searchHits;
private SearchSourceBuilder searchSourceBuilder;
@Before
public void init() {
searchRequest = new SearchRequest();
searchRequest.indices("test");
searchRequest.types("course");
}
//查询文档
@Test
public void getDoc() throws IOException {
GetRequest getRequest = new GetRequest("test", "course", "1");
GetResponse getResponse = restHighLevelClient.get(getRequest);
boolean exists = getResponse.isExists();
System.out.println(exists);
String sourceAsString = getResponse.getSourceAsString();
System.out.println(sourceAsString);
}
//match_all查询
@Test
public void testMatchAll() throws IOException {
//创建 参数构造器
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchAllQuery());
searchRequest.source(searchSourceBuilder);
searchResponse = restHighLevelClient.search(searchRequest);
}
//分页查询
//from起始条数
//size查询条数
@Test
public void testPage() throws IOException {
//创建 参数构造器
searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.from(1);
searchSourceBuilder.size(5);
searchSourceBuilder.sort("price", SortOrder.ASC);
searchRequest.source(searchSourceBuilder);
searchResponse = restHighLevelClient.search(searchRequest);
}
//检索查询-->指定单一type
//operator :or 表示 只要有一个词在文档中出现则就符合条件,and表示每个词都在文档中出现则才符合条件。
@Test
public void testMatch() throws IOException {
searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchQuery("name", "spring开发").operator(Operator.AND));
searchRequest.source(searchSourceBuilder);
searchResponse = restHighLevelClient.search(searchRequest);
}
//检索查询-->指定多个type
//matchQuery是在一个field中去匹配,multiQuery是拿关键字去多个Field中匹配。
@Test
public void testMultiMatch() throws IOException {
searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.multiMatchQuery("开发", "name", "description"));
searchRequest.source(searchSourceBuilder);
searchResponse = restHighLevelClient.search(searchRequest);
}
//检索查询
//布尔查询对应于Lucene的BooleanQuery查询,实现将多个查询组合起来。
// 参数:
// must:表示必须,多个查询条件必须都满足。(通常使用must)
// should:表示或者,多个查询条件只要有一个满足即可。
// must_not:表示非。
@Test
public void testBooleanMatch() throws IOException {
searchSourceBuilder = new SearchSourceBuilder();
//json条件
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(QueryBuilders.matchQuery("name","开发"));
boolQueryBuilder.must(QueryBuilders.rangeQuery("price").gte("50").lte(100));
searchSourceBuilder.query(boolQueryBuilder);
searchRequest.source(searchSourceBuilder);
searchResponse = restHighLevelClient.search(searchRequest);
}
//检索查询
//过滤查询。此操作实际上就是 query DSL 的补充语法。
// 过滤的时候,不进行任何的匹配分数计算
// 相对于 query 来说,filter 相对效率较高。
// Query 要计算搜索匹配相关度分数。Query更加适合复杂的条件搜索。
@Test
public void testFilter() throws IOException {
searchSourceBuilder = new SearchSourceBuilder();
//json条件
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(QueryBuilders.matchQuery("name","开发"));
boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(10).lte(100));
searchSourceBuilder.query(boolQueryBuilder);
searchRequest.source(searchSourceBuilder);
searchResponse = restHighLevelClient.search(searchRequest);
}
@After
public void show() {
searchHits = searchResponse.getHits();
long totalHits = searchHits.getTotalHits();
System.out.println("共搜索到" + totalHits + "条文档");
SearchHit[] hits = searchHits.getHits();
for (SearchHit hit : hits) {
System.out.println(hit.getSourceAsString());
}
}
/**
* 高亮查询及遍历
*/
@Test
public void testHighLightQuery() throws IOException {
searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchQuery("name","spring"));
//设置高亮
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.preTags("<font color='red'>");
highlightBuilder.postTags("</font>");
highlightBuilder.field("name");
searchSourceBuilder.highlighter(highlightBuilder);
searchRequest.source(searchSourceBuilder);
searchResponse = restHighLevelClient.search(searchRequest);
SearchHits searchResponseHits = searchResponse.getHits();
SearchHit[] hits = searchResponseHits.getHits();
for (int i = 0; i < hits.length; i++) {
SearchHit hit = hits[i];
/* String id = hit.getId();
System.out.println("id:" + id);
String source = hit.getSourceAsString();
System.out.println(source);*/
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
if (highlightFields!=null){
HighlightField highlightField = highlightFields.get("name");
Text[] fragments = highlightField.getFragments();
System.out.println(fragments[0].toString());
}
}
}
}