Elasticsearch 简单使用
ES 客户端创建及引用
RestHighLevelClient 方式
@Bean
public RestHighLevelClient restHighLevelClient() {
return new RestHighLevelClient(
RestClient.builder(
Arrays.stream(StringUtils.split(ipAddress,
",")).map(HttpHost::create).toArray(HttpHost[]::new)
)
);
}
// 引用使用
@Resource
private RestHighLevelClient restHighLevelClient;
复制代码
ElasticsearchTemplate 方式
@Resource
private ElasticsearchTemplate elasticsearchTemplate;
复制代码
SpringbootData Repository 方式
1. 实体对象
@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(indexName = CenterShopifyMailAnalysisMessageDO.INDEX_NAME)
public class CenterShopifyMailAnalysisMessageDO {
/**
* 索引名称
*/
public static final String INDEX_NAME = "shopify_mail_analysis_message";
/**
* 主键
*/
@Id
private String id;
}
复制代码
2. 创建Mapper
@Repository
public interface CenterShopifyMailAnalysisMessageRepository extends ElasticsearchRepository<CenterShopifyMailAnalysisMessageDO, String> {
/**
* 原始索引ID
*
* @param refOriginalMessageId
* @return CenterShopifyMailAnalysisMessageDO
*/
CenterShopifyMailAnalysisMessageDO findByRefOriginalMessageId(String refOriginalMessageId);
/**
* 查询总条数
*
* @return 总条数
*/
int countAllBy();
}
复制代码
3. 引用使用
@Resource
private CenterShopifyMailAnalysisMessageRepository centerShopifyMailAnalysisMessageRepository;
复制代码
ES 查询常用方法汇总
方法 | 说明 |
---|---|
filter | 不计算评分, 查询效率高,有缓存 (推荐) |
must | 要计算评分,查询效率低,无缓存 |
must_not | 条件不需要满足 |
term | 不会对输入得内容进行分词 |
match | 会对输入得内容进行分词 |
matchPhrase | 短语匹配查询,ES引擎首先分析查询字符串,从分析后的文本中构建短语查询,这意味着必须匹配短语中的所有分词,并且保证各个分词的相对位置不变 |
wildcard | 通配符查询,*:表示o个或多个字符,?: 表示单个字符; 类似于mysql 中得 like 查询 |
range | gte:大于等于,gt:大于,lte: 小于等于,lt:小于,from-to 相当于 between |
exists | 查询文档中是否包含field 指定的字段,例如:查询不为null :builder.must(QueryBuilders.existsQuery("字段名"));查询不为空字符串 builder.mustNot(QueryBuilders.termQuery("字段名", "")); |
prefix | 匹配分词前缀 如果字段没分词,就匹配整个字段前缀 |
idx | 根据id查询 |
FetchSourceFilterBuilder : 对象可以设置哪些属性输出哪些不输出 复制代码
Script: 可以用作查询也可以用作排序
查询:
// 查询当前时间-sentDateTime >= 86400000 的数据
Script script = new Script("new Date().getTime() - doc['sentDateTime'].value >= 86400000");
builder.filter(QueryBuilders.scriptQuery(script));
排序:
// replyStatus为0时,sentDateTime按从小到大排序,replyStatus不为0时,sentDateTime按从大到小排序
Script script = new Script("if(doc['replyStatus'].value == 0){return doc['sentDateTime'].value * -1 }else{return doc['sentDateTime'].value}");
ScriptSortBuilder scriptSortBuilder = SortBuilders.scriptSort(script, ScriptSortBuilder.ScriptSortType.NUMBER).order(SortOrder.DESC);
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(builder)
.withSort(scriptSortBuilder
.build();
复制代码
ES 查询示例
term 查询:
term做精确查询可以用它来处理数字,布尔值,日期以及文本。查询数字时问题不大,但是当查询字符串时会有问题。term查询的含义是termQuery会去倒排索引中寻找确切的term,但是它并不知道分词器的存在。term表示查询字段里含有某个关键词的文档,terms表示查询字段里含有多个关键词的文档。也就是说直接对字段进行term本质上还是模糊查询,只不过不会对搜索的输入字符串进行分词处理罢了。如果想通过term查到数据,那么term查询的字段在索引库中就必须有与term查询条件相同的索引词,否则无法查询到结果。
一句话解释: elasticsearch 里默认的IK分词器是会将每一个中文都进行了分词的切割,所以你直接想查一整个词,或者一整句话是无返回结果的。
关于keyword:
我看有的文章说设置该属性用于关键词搜索,不进行分词。对于字符串类型的字段,es会默认生成一个keyword字段用于精确搜索。也有的说实际上还是会分词,只不过keyword的设置增加了一个额外字段,该字段就是filename.keyword。这个keyword才是不分词的索引字段,也就真正意义上实现了不分词处理字段。索引也是索引该字段才生成真正的精确匹配。至于分不分词实验一下就好了。感觉他们想表达的意思差不多是filename.keyword不分词,但是filename还是会分词。
public ResponseResult<List<CenterShopifyMailAnalysisMessageVO>> queryPage(CenterShopifyEmailReqVO entity) {
BoolQueryBuilder builder = QueryBuilders.boolQuery();
// 精确查询
builder.filter(QueryBuilders.termQuery("websiteId", entity.getWebsiteId()));
// 如果用term查询字符串的话,请注意上面引用语句,否则可能导致查询到意想不到的结果,term 字符串精确查询的话,用keyword
// 字符串精确查询
builder.filter(QueryBuilders.termQuery("name.keyword", entity.getName));
// 时间范围查询, between
builder.filter(QueryBuilders.rangeQuery(CenterShopifyMailConstant.SENT_DATETIME)
.from(DateUtil.parseDateTime(entity.getStartTime()).getTime())
.to(DateUtil.parseDateTime(entity.getEndTime()).getTime()));
// 发件人,模糊查询,例如 like '%xx%'
builder.filter(QueryBuilders.wildcardQuery("sendAddress.keyword", "*" +
centerShopifyEmailReqVO.getFromBy() + "*"));
// 主题,模糊查询,默认中文分词,和 like 有区别
builder.filter(QueryBuilders.matchPhraseQuery("subject", entity.getSubject()));
// 订单 例如: and ( orderNo=xx or orderNo=xx )
BoolQueryBuilder order = new BoolQueryBuilder();
entity.getOrderNoList().forEach(o -> order.should(QueryBuilders.matchPhraseQuery("orderNo", o)));
builder.filter(order);
// 标签 例如: and ( refLabelId like '%xx%' and refLabelId like '%xx%' )
entity.getLabelIds().forEach(o ->
builder.must(QueryBuilders.wildcardQuery("refLabelId.keyword",
"*" + o +"*")));
if (centerShopifyEmailReqVO.getFinishStart() == 3) {
// 24 小时内未处理
Script script = new Script("new Date().getTime() - doc['sentDateTime'].value < 86400000");
builder.filter(QueryBuilders.scriptQuery(script));
} else if (centerShopifyEmailReqVO.getFinishStart() == 4) {
// 大于24小时未处理
Script script = new Script("new Date().getTime() - doc['sentDateTime'].value >= 86400000");
builder.filter(QueryBuilders.scriptQuery(script));
}
// 排序 replyStatus=0,sentDateTime从小到大排序, 等于0 乘以-1的目的是让返回的数值调个个儿
// replyStatus≠0,sentDateTime从大到小排序,
Script script = new Script("if(doc['replyStatus'].value == 0){return doc['sentDateTime'].value * -1
}else{return doc['sentDateTime'].value}");
ScriptSortBuilder scriptSortBuilder = SortBuilders.scriptSort(script,
ScriptSortBuilder.ScriptSortType.NUMBER).order(SortOrder.DESC);
// body 设置不输出
FetchSourceFilterBuilder fetchSourceFilterBuilder = new FetchSourceFilterBuilder();
fetchSourceFilterBuilder.withExcludes(CenterShopifyMailConstant.BODY);
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(builder)
.withSort(SortBuilders.fieldSort(CenterShopifyMailConstant.STATUS).order(SortOrder.ASC))
.withSort(scriptSortBuilder)
.withSourceFilter(fetchSourceFilterBuilder.build())
.withPageable(PageRequest.of(entity.getCurrentPage() - 1, entity.getPageSize()))
.build();
AggregatedPage<CenterShopifyMailAnalysisMessageDO> centerShopifyMailAnalysisMessageDOS =
elasticsearchTemplate.queryForPage(searchQuery,
CenterShopifyMailAnalysisMessageDO.class);
// content 返回数据,getTotalElements 总条数
return ResponseResult.successPage(content, centerShopifyMailAnalysisMessageDOS.getTotalElements(),
centerShopifyEmailReqVO.getCurrentPage(),
centerShopifyEmailReqVO.getPageSize());
}
复制代码