目录
版本
下载地址
ElasticSearch频繁报503错误
开放 9300 和 9200 两个端口
测试联通性
改动包装类
elasticsearchTemplate
getAllRespRepository
封装elasticsearchService
业务逻辑
版本
首先要对应版本
这是我在官网找到的版本信息
一定要 springboot 和 es 相互对应
下载地址
Past Releases of Elastic Stack Software | Elastic
ElasticSearch频繁报503错误
# 开启跨域访问支持,默认为false
http.cors.enabled: true
# 跨域访问允许的域名地址
http.cors.allow-origin: "*"
# 通过为 cluster.initial_master_nodes 参数设置符合主节点条件的节点的 IP 地址来引导启动集群
cluster.initial_master_nodes: ["node-1"]
开放 9300 和 9200 两个端口
关于ElasticSearch的9200和9300端口区别
9200作为Http协议,主要用于外部通讯
9300作为Tcp协议,jar之间就是通过tcp协议通讯
ES集群之间是通过9300进行通讯
测试联通性
linux 上启动服务
使用客户端 es-client
改动包装类
要使其变为 elasticsearch 可以识别的包装类
@Document 类注解中标注其索引(在 elasticsearch 中指的是表名)、
@Id 主键注解
@Field 字段注解中打上标识 表示elasticsearch中可能要进行全文搜索的字段
package work.dduo.ans.model.vo.response;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.*;
import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(indexName = "sentences")
public class GetAllContentResp {
@Id
private Integer id;
@Field(type = FieldType.Text) // elasticsearch中可能要进行全文搜索的字段
private String content;
private Date createTime;
@Field(type = FieldType.Text) // elasticsearch中可能要进行全文搜索的字段
private String from;
private String hot;
private String other1;
private String other2;
private String other3;
}
elasticsearchTemplate
elasticsearchTemplate 是 Java 提供的模版工具类
我们主要用其 search 方法来查询
getAllRespRepository
存储库
类似于 mybatis
我们通过一个类继承 ElasticsearchRepository
来直接调用父类方法中的增删改查方法
package work.dduo.ans.elasticsearch.repository;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import work.dduo.ans.model.vo.response.GetAllContentResp;
// 该接口提供了基本的CRUD操作。
public interface GetAllRespRepository extends ElasticsearchRepository<GetAllContentResp, Integer> {
}
注意我们要将包装类和主键类型作为参数传入
封装elasticsearchService
package work.dduo.ans.elasticsearch.service;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import work.dduo.ans.elasticsearch.repository.GetAllRespRepository;
import work.dduo.ans.model.vo.response.GetAllContentResp;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class ElasticsearchService {
@Autowired
private ElasticsearchOperations elasticsearchTemplate;
@Autowired
private GetAllRespRepository getAllRespRepository;
/**
* 更新数据到elasticsearch
*
* @param getAllResp
* @return
*/
public List<GetAllContentResp> saveProduct(List<GetAllContentResp> getAllResp) {
// 把传入的数据 存入elasticsearch
return (List<GetAllContentResp>) getAllRespRepository.saveAll(getAllResp);
}
/**
* 单字符串全文查询,支持分页和排序 查询包括字符串的所有数据 所有字段
*
* @param queryString 查询字符串
* @param page 页码
* @param size 每页数量
* @return 查询结果列表
*/
public List<GetAllContentResp> fullTextSearch(String queryString, int page, int size) {
// 构建查询条件
QueryBuilder queryBuilder = QueryBuilders.queryStringQuery(queryString);
// 构建搜索查询,设置分页和排序
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(queryBuilder)
.withPageable(PageRequest.of(page, size))
.withSort(SortBuilders.fieldSort("id").order(SortOrder.ASC)) // 按照id排序 正序
.build();
// 执行查询
SearchHits<GetAllContentResp> searchHits = elasticsearchTemplate.search(searchQuery, GetAllContentResp.class);
// 提取查询结果
return searchHits.getSearchHits().stream()
.map(SearchHit::getContent)
.collect(Collectors.toList());
}
/**
* 某字段按字符串模糊查询 只查询指定字段
*
* @param field 字段名
* @param value 查询值
* @param page 页码
* @param size 每页数量
* @return 查询结果列表
*/
public List<GetAllContentResp> fuzzySearchByField(String field, String value, int page, int size) {
// 构建模糊查询条件
QueryBuilder queryBuilder = QueryBuilders.matchQuery(field, value);
// 构建搜索查询,设置分页
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(queryBuilder)
.withPageable(PageRequest.of(page, size))
.build();
// 执行查询
SearchHits<GetAllContentResp> searchHits = elasticsearchTemplate.search(searchQuery, GetAllContentResp.class);
// 提取查询结果
return searchHits.getSearchHits().stream()
.map(SearchHit::getContent)
.collect(Collectors.toList());
}
/**
* PhraseMatch 查询(短语匹配)
*
* @param field 字段名
* @param phrase 短语
* @param slop 允许的最大间隔
* @param page 页码
* @param size 每页数量
* @return 查询结果列表
*/
public List<GetAllContentResp> phraseMatchSearch(String field, String phrase, int slop, int page, int size) {
// 构建短语匹配查询条件
QueryBuilder queryBuilder = QueryBuilders.matchPhraseQuery(field, phrase).slop(slop);
// 构建搜索查询,设置分页
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(queryBuilder)
.withPageable(PageRequest.of(page, size))
.build();
// 执行查询
SearchHits<GetAllContentResp> searchHits = elasticsearchTemplate.search(searchQuery, GetAllContentResp.class);
// 提取查询结果
return searchHits.getSearchHits().stream()
.map(SearchHit::getContent)
.collect(Collectors.toList());
}
/**
* Term 查询(精确查询)
*
* @param field 字段名
* @param value 查询值
* @param page 页码
* @param size 每页数量
* @return 查询结果列表
*/
public List<GetAllContentResp> termSearch(String field, Object value, int page, int size) {
// 构建精确查询条件
QueryBuilder queryBuilder = QueryBuilders.termQuery(field, value);
// 构建搜索查询,设置分页
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(queryBuilder)
.withPageable(PageRequest.of(page, size))
.build();
// 执行查询
SearchHits<GetAllContentResp> searchHits = elasticsearchTemplate.search(searchQuery, GetAllContentResp.class);
// 提取查询结果
return searchHits.getSearchHits().stream()
.map(SearchHit::getContent)
.collect(Collectors.toList());
}
/**
* multi_match 多个字段匹配某字符串
*
* @param fields 字段数组
* @param value 查询值
* @param page 页码
* @param size 每页数量
* @return 查询结果列表
*/
public List<GetAllContentResp> multiMatchSearch(String[] fields, String value, int page, int size) {
// 构建多字段匹配查询条件
QueryBuilder queryBuilder = QueryBuilders.multiMatchQuery(value, fields);
// 构建搜索查询,设置分页
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(queryBuilder)
.withPageable(PageRequest.of(page, size))
.build();
// 执行查询
SearchHits<GetAllContentResp> searchHits = elasticsearchTemplate.search(searchQuery, GetAllContentResp.class);
// 提取查询结果
return searchHits.getSearchHits().stream()
.map(SearchHit::getContent)
.collect(Collectors.toList());
}
/**
* 完全包含查询
*
* @param field 字段名
* @param value 查询值
* @param operator 操作符(如 AND、OR)
* @param minimumShouldMatch 最少匹配百分比
* @param page 页码
* @param size 每页数量
* @return 查询结果列表
*/
public List<GetAllContentResp> exactMatchSearch(String field, String value, String operator, String minimumShouldMatch, int page, int size) {
// 构建匹配查询条件
QueryBuilder queryBuilder = QueryBuilders.matchQuery(field, value)
.operator(Operator.fromString(operator))
.minimumShouldMatch(minimumShouldMatch);
// 构建搜索查询,设置分页
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(queryBuilder)
.withPageable(PageRequest.of(page, size))
.build();
// 执行查询
SearchHits<GetAllContentResp> searchHits = elasticsearchTemplate.search(searchQuery, GetAllContentResp.class);
// 提取查询结果
return searchHits.getSearchHits().stream()
.map(SearchHit::getContent)
.collect(Collectors.toList());
}
/**
* 合并查询(boolQuery) 并集
*
* @param mustField 必须匹配的字段
* @param mustValue 必须匹配的值
* @param filterField 过滤字段
* @param filterValue 过滤值
* @param shouldField 可选匹配的字段
* @param shouldValues 可选匹配的值数组
* @param page 页码
* @param size 每页数量
* @return 查询结果列表
*/
public List<GetAllContentResp> boolQuerySearch(String mustField, String mustValue, String filterField, Object filterValue, String shouldField, List<Object> shouldValues, int page, int size) {
// 构建布尔查询
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
// 添加 must 条件
boolQuery.must(QueryBuilders.matchQuery(mustField, mustValue));
// 添加 filter 条件
boolQuery.filter(QueryBuilders.termQuery(filterField, filterValue));
// 添加 should 条件
for (Object shouldValue : shouldValues) {
boolQuery.should(QueryBuilders.termQuery(shouldField, shouldValue));
}
// 构建搜索查询,设置分页
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(boolQuery)
.withPageable(PageRequest.of(page, size))
.build();
// 执行查询
SearchHits<GetAllContentResp> searchHits = elasticsearchTemplate.search(searchQuery, GetAllContentResp.class);
// 提取查询结果
return searchHits.getSearchHits().stream()
.map(SearchHit::getContent)
.collect(Collectors.toList());
}
/**
* 某两个字段按字符串模糊查询 只查询指定字段
*
*
* @param field1 第一个字段名
* @param value1 第一个查询值
* @param field2 第二个字段名
* @param value2 第二个查询值
* @param page 页码
* @param size 每页数量
* @return 查询结果列表
*/
public List<GetAllContentResp> fuzzySearchByTwoFields(String field1, String value1, String field2, String value2, int page, int size) {
// 构建第一个字段的模糊查询条件
MatchQueryBuilder queryBuilder1 = QueryBuilders.matchQuery(field1, value1);
// 构建第二个字段的模糊查询条件
MatchQueryBuilder queryBuilder2 = QueryBuilders.matchQuery(field2, value2);
// 使用 bool 查询将两个查询条件组合起来 并集
// BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
// .should(queryBuilder1)
// .should(queryBuilder2);
// 使用 bool 查询将两个查询条件组合起来 交集
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
.must(queryBuilder1)
.must(queryBuilder2);
// 构建搜索查询,设置分页
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(boolQueryBuilder)
.withPageable(PageRequest.of(page, size))
.build();
// 执行查询
SearchHits<GetAllContentResp> searchHits = elasticsearchTemplate.search(searchQuery, GetAllContentResp.class);
// 提取查询结果
return searchHits.getSearchHits().stream()
.map(SearchHit::getContent)
.collect(Collectors.toList());
}
}
业务逻辑
写入功能
同步 es 的数据
/**
* 更新数据到elasticsearch
*
* @param getAllResp
* @return
*/
public List<GetAllContentResp> saveProduct(List<GetAllContentResp> getAllResp) {
// 把传入的数据 存入elasticsearch
return (List<GetAllContentResp>) getAllRespRepository.saveAll(getAllResp);
}
搜索功能
客制化搜索
/**
* 查询句子数据
*
* @param queryWordsResp
* @return
*/
@Override
public List<GetAllContentResp> queryWords(QueryWordsResp queryWordsResp) {
// 根据传入的参数是匹配不同的查询类型
if (StrUtil.isBlank(queryWordsResp.getContent()) && StrUtil.isBlank(queryWordsResp.getFrom())) {
// 传了两个空值进来 走缓存->走数据库
return tSentencesMapper.getAll();
} else if (StrUtil.isBlank(queryWordsResp.getFrom())) {
// 只传了content 走elasticsearch 模糊查询
String content = queryWordsResp.getContent();
List<GetAllContentResp> results = elasticsearchService.fuzzySearchByField("content", content, 0, 10);
return results;
} else if (StrUtil.isBlank(queryWordsResp.getContent())) {
// 只穿了from 走elasticsearch 模糊查询
String from = queryWordsResp.getFrom();
// 注意英文名称难以分词 就会出现不能模糊查询的缺点
List<GetAllContentResp> results = elasticsearchService.fuzzySearchByField("from", from, 0, 10);
return results;
} else {
// 两个字段都有数值 走elasticsearch
List<GetAllContentResp> results = elasticsearchService.fuzzySearchByTwoFields(
"content", queryWordsResp.getContent(),
"from", queryWordsResp.getFrom(),
0, 10);
return results;
}
}