Elasticsearch 入门级简单使用

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());
}
复制代码

猜你喜欢

转载自juejin.im/post/7018078585780961316