ElasticSearch是一个基于Lucene的开源的、分布式实时搜索和分析引擎。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。
上一节我们以及安装好了elasticsearch以及kibana、IK分词器
现在让我们看看如何在springboot工程中使用吧。
安装依赖
我们使用的是7.x,注意7.x和8.x的差别较大,初学者可以先从7.x入手。
XML
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.12.1</version>
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>7.12.1</version>
</dependency>
es配置
yml文件配置
XML
elasticsearch:
hostlist: 你的es服务ip #多个结点中间用逗号分隔
article:
index: article
source_fields: id,title,content,summary,thumbnail,categoryId,isTop,status,viewCount,isComment,createTime
java
@Configuration
public class ElasticsearchConfig {
@Value("${elasticsearch.hostlist}")
private String hostlist;
@Bean
public RestHighLevelClient restHighLevelClient() {
//解析hostlist配置信息
String[] split = hostlist.split(",");
//创建HttpHost数组,其中存放es主机和端口的配置信息
HttpHost[] httpHostArray = new HttpHost[split.length];
for (int i = 0; i < split.length; i++) {
String item = split[i];
httpHostArray[i] = new HttpHost(item.split(":")[0], Integer.parseInt(item.split(":")[1]), "http");
}
//创建RestHighLevelClient客户端
return new RestHighLevelClient(RestClient.builder(httpHostArray));
}
}
索引
定义service接口
java
public interface IndexService {
/**
* 添加文章索引
* @param
* @return
*/
public Boolean addArticleIndex(String indexName, String id, Object object);
}
实现service接口
java
@Service
@Slf4j
public class IndexServiceImpl implements IndexService {
@Resource
RestHighLevelClient client;
@Override
public Boolean addArticleIndex(String indexName, String id, Object object) {
// 格式化日期
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = sdf.format(((Article) object).getCreateTime());
// 将格式化后的日期字符串替换 JSON 字符串中的 createTime 字段
JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(object));
jsonObject.put("createTime", dateString);
String jsonString = jsonObject.toJSONString();
// String jsonString = JSON.toJSONString(object);
IndexRequest indexRequest = new IndexRequest(indexName).id(id);
//指定索引文档内容
indexRequest.source(jsonString, XContentType.JSON);
//索引响应对象
IndexResponse indexResponse = null;
try {
indexResponse = client.index(indexRequest, RequestOptions.DEFAULT);
} catch (IOException e) {
log.error("添加索引出错:{}", e.getMessage());
e.printStackTrace();
ZhiWenPlusException.cast("添加索引出错");
}
String name = indexResponse.getResult().name();
System.out.println(name);
return name.equalsIgnoreCase("created") || name.equalsIgnoreCase("updated");
}
}
创建索引接口
java
@RestController
@RequestMapping("search/index")
public class ArticleIndexController {
@Value("${elasticsearch.article.index}")
private String courseIndexStore;
@Resource
private IndexService indexService;
@ApiOperation(value = "添加文章索引")
@PostMapping("/article")
public Boolean addIndex(@RequestBody Article article) {
Long id = article.getId();
if (id == null) {
ZhiWenPlusException.cast("文章id为空");
}
Boolean result = indexService.addArticleIndex(courseIndexStore, String.valueOf(id), article);
if (!result) {
ZhiWenPlusException.cast("添加课程索引失败");
}
return result;
}
}
搜索
根据关键字搜索文章信息,搜索方式为全文检索,关键字需要匹配文章的标题、简介,并且高亮显示。
定义service接口
java
public interface ArticleSearchService {
/**
* 搜索文章信息
* @param pageNo
* @param pageSize
* @param keyWords
* @return
*/
ResponseResult queryArticleIndex(Long pageNo, Long pageSize, String keyWords);
}
实现service接口
java
@Service
@Slf4j
public class ArticleSearchServiceImpl implements ArticleSearchService {
@Value("${elasticsearch.article.index}")
private String courseIndexStore;
@Value("${elasticsearch.article.source_fields}")
private String sourceFields;
@Resource
RestHighLevelClient client;
@Override
public ResponseResult queryArticleIndex(Long pageNo, Long pageSize,String keyWords) {
//设置索引
SearchRequest searchRequest = new SearchRequest(courseIndexStore);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//source源字段过虑
String[] sourceFieldsArray = sourceFields.split(",");
searchSourceBuilder.fetchSource(sourceFieldsArray, new String[]{});
if (StringUtils.isNotEmpty(keyWords)) {
//匹配关键字
MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(keyWords, "title", "summary");
//设置匹配占比
multiMatchQueryBuilder.minimumShouldMatch("70%");
//提升另个字段的Boost值
multiMatchQueryBuilder.field("title", 10);
boolQueryBuilder.must(multiMatchQueryBuilder);
}
int start = (int) ((pageNo - 1) * pageSize);
searchSourceBuilder.from(start);
searchSourceBuilder.size(Math.toIntExact(pageSize));
//布尔查询
searchSourceBuilder.query(boolQueryBuilder);
//高亮设置
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.preTags("<font class='eslight'>");
highlightBuilder.postTags("</font>");
//设置高亮字段
highlightBuilder.fields().add(new HighlightBuilder.Field("title"));
searchSourceBuilder.highlighter(highlightBuilder);
//请求搜索
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = null;
try {
searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
} catch (IOException e) {
e.printStackTrace();
log.error("课程搜索异常:{}", e.getMessage());
// return new SearchPageResultDto<CourseIndex>(new ArrayList(), 0, 0, 0);
ZhiWenPlusException.cast("课程搜索异常");
}
//结果集处理
SearchHits hits = searchResponse.getHits();
SearchHit[] searchHits = hits.getHits();
//记录总数
TotalHits totalHits = hits.getTotalHits();
//数据列表
List<Article> list = new ArrayList<>();
for (SearchHit hit : searchHits) {
String sourceAsString = hit.getSourceAsString();
Article article = JSON.parseObject(sourceAsString, Article.class);
//取出source
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
//课程id
Long id = article.getId();
//取出名称
String title = article.getTitle();
//取出高亮字段内容
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
if (highlightFields != null) {
HighlightField nameField = highlightFields.get("title");
if (nameField != null) {
Text[] fragments = nameField.getFragments();
StringBuffer stringBuffer = new StringBuffer();
for (Text str : fragments) {
stringBuffer.append(str.string());
}
title = stringBuffer.toString();
}
}
article.setId(id);
article.setTitle(title);
list.add(article);
}
return new ResponseResult().ok(list);
}
}
创建搜索接口
java
@RestController
@RequestMapping("search/article")
public class ArticleSearchController {
@Resource
private ArticleSearchService articleSearchService;
@GetMapping("/list")
public ResponseResult searchArticle(Long pageNum, Long pageSize,String keywords) {
ResponseResult result = articleSearchService.queryArticleIndex(pageNum, pageSize, keywords);
return result;
}
}