ElasticSearch查询框架-类Mybatis-plus式调用

Elasticsearch-helper是一个用于简化Elasticsearch查询的框架,主要针对查询场景进行封装,适用于存在大量查询条件的系统。通过注解方式描述查询条件,提供Request和Response钩子接口进行扩展。项目包括查询对象、返回对象定义、被代理接口的使用示例,以及如何扩展更多查询类型和处理方法。此外,还支持高亮配置和自定义聚合查询。
摘要由CSDN通过智能技术生成

ElasticSearch-helper

使用ElasticSearch作为分析,检索的数据源进行开发已经有一段时间了,经历了大大小小的几个项目,从初次接触这个技术,惊叹于它巧妙的设计,同时也惊叹它恶心的访问api;在初学时我时常会望着前辈开发的绵绵不觉的链式调用无所适从,到处寻找需要调整的参数;之后在一个项目中我遇到了一个逆天的搜索框,条件密密麻麻达几十个之多,过滤,模糊,范围应有竟有(不讨论设计的合理性,也许存在即合理吧),于是那个搜索方法的代码行数被干到了1000+,于是我在想是不是可以设计这样一个框架,将es的查询语句用对象来描述,让查询条件的实体类自己来说明自己想要做什么样的查询,因此我开发了Elasticsearch-helper。

项目地址仓库地址:https://gitee.com/JohenTeng/elasticsearch-helper.git
使用示例地址:https://gitee.com/JohenTeng/elasticsearch-helper-sample.git

适应场景

elasticsearch-helper主要是针对查询进行了封装,当前版对DDL以及增删改的支持主要体现于类Mybait-plus的基类方法中实现,该框架适用于使用ElasticSearch作为数据源,且存在大量查询条件的系统。

结构

在这里插入图片描述
EsQueryEngine: 接受查询对象,生成es查询对象,该对象需要使用 @EsQueryIndex 描述对象,使用 org/pippi/elasticsearch/helper/core/beans/annotation/query/module 下的注解描述属性: @Match,@MultiMatch,@Term … …

RequestHook: 扩展接口,实现Request描述的扩展
ResponseHook: 扩展接口,自定义解读 es 的 SearchResponse

使用方法

主方法中:
@EnableEsHelper // 启用EsHelper框架 
@SpringBootApplication(scanBasePackages = "com.sun")
public class SampleApplication {
    public static void main(String[] args) {
        SpringApplication.run(SampleApplication.class, args);
    }
}
在 spring-boot配置中定义:

.properties 配置:
## 配置日志是否打印 elasticsearch的查询语句
es.helper.queryLogOut.enable = true 
## 配置自定义处理类所在位置:
es.helper.ext.handle-packages = *** 

.yml 配置:
es:
  helper:
    queryLogOut:
      enable: true
    ext:
      handle-packages: com.***.***.handles1,com.***.***.handles2 

方式一 类Mybatis-plus的ES查询API(v2.0.0新增)

定义 ES 索引映射的java实体类,集成EsEntity 基类
@Data
@EsIndex("account")
public class AccountEntity extends EsEntity implements Serializable {

	private Integer accountNumber;

	private Integer balance;

	private String firstname;

	private String lastname;

	private Integer age;

	private String gender;

	private String address;

	private String employer;

	private String email;

	private String city;

	private String state;
}
定义查询 mapper接口 继承 org.pippi.elasticsearch.helper.model.annotations.mapper.EsMapper;
@EsMapper
public interface EsAccountMapper extends EsBaseMapper<AccountEntity> {
}
在实际查询中使用 mapper 进行Es查询
@RunWith(SpringRunner.class)
@SpringBootTest(classes = EsHelperSampleApplication.class)
public class AccountLambdaQueryTest {

    @Resource
    private EsAccountMapper accountMapper;

    @Resource
    private EsMoviesMapper moviesMapper;

    @Test
    public void aggTest() {
        AggRes aggRes = accountMapper.selectAgg(EsWrappers.lambdaQuery(AccountEntity.class)
                .term(AccountEntity::getGender, "F")
                .agg(AggregationBuilders.terms("_city_distribution").field("city").size(1000)
                        .subAggregation(AggregationBuilders.count("_person_count").field("city"))));
        System.out.println(JacksonUtils.parseObjToJsonPretty(aggRes.fetchByPath("$._city_distribution.Nogal")));
    }

    @Test
    public void termTest() {
        List<AccountEntity> list = accountMapper.selectList(EsWrappers.lambdaQuery(AccountEntity.class)
                .term(AccountEntity::getFirstname, "Dena"));
        System.out.println(JacksonUtils.parseObjToJsonPretty(list));
    }

方式二 查询bean描述ES查询行为

查询对象:

@EsQueryIndex(index = "test", model = QueryModel.BOOL)
// 是否启用高亮
@HighLight(fields = {"title", "describe"}) 
public class DemoSearchParam {
    // 范围查询
    @Range(value = @Base, tag = Range.LE_GE)
    private RangeParam intensity;
    
    @MultiMatch(value = @Base,fields = {"title", "describe"})
    private String title;
}
返回对象:
// 默认的查询结果处理结果类需要 继承 BaseResp.BaseHit
public class Content extends BaseResp.BaseHit {

    private int intensity;

    private String title;
}

被代理接口:
@EsHelperProxy
public interface TestQueryService {
    BaseResp<Content> queryRecordByIntensity(ContentSearchParam param)
}

调用:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SampleApplication.class)
public class TestQueryBeanServiceTest {

    @Resource
    private TestQueryService testQueryService;

    @Test
    public void testQueryService(){
        ContentSearchParam param = new ContentSearchParam();
        RangeParam rangeParam = new RangeParam();
        rangeParam.setLeft(12);
        rangeParam.setRight(15);
        param.setIntensity(rangeParam);
        param.setTitle("测试测试");
        BaseResp<Content> baseResp = testQueryService.queryRecordByIntensity(param);
        System.out.println(SerializerUtils.parseObjToJson(baseResp));
    }

}

方式三 在方法参数中使用 Es查询注解,实现Es查询

@EsMapper
public interface EsHandleMapper {

    @EsAnnQueryIndex(index = "account")
    List<AccountEntity> methodQueryTest(@Gte Integer age,
                                        @Terms(@Base("firstname.keyword")) String ... firstname);
}
该方式是对Bean实现Es查询的一种扩展,避免简单查询也必须要定义一个 Es的查询bean;

扩展

=> 包:org.pippi.elasticsearch.helper.core.beans.annotation.query.mapping.extend下定义的类:
MoreLikeThisParam:@MoreLikeThis修饰的类属性需要定义为该类型;
PageParam:@PageAndOrder修饰的类属性需要定义为该类型;
RangeParam:@Range修饰的类属性需要定义为该类型;

=> 关于钩子方法:
包:org.pippi.elasticsearch.helper.core.hook
作用:我们无法定义所有的查询场景,因此需要使用钩子方法来自定义查询类以及结果处理方法
接口:
@FunctionalInterface RequestHook#handleRequest
@FunctionalInterface ResponseHook#handleResponse

我们可以通过让查询对象 继承 HookQuery抽象类,实现其中的set方法,如:

public class DemoParam extends HookQuery {
    
    @Match(value = @Base)
    private String Field;
    
    @Override
    public void setRequestHook() {
        super.requestHook = (h, p) -> h;
    }
    @Override
    public void setResponseHook() {
        super.responseHook = resp -> null;
    }
}

或者 在代码中定义公共的钩子方法,如:
public interface MySearchHooks extends UserHooks {
    RequestHook reqHook1 = (h, p) -> h;
    ResponseHook respHook1 = resp -> null;
}
使用:
@EsHelperProxy
public interface TestQueryService {
    // 查询在处理了 查询类中的注解定义之后会执行 RequestHook 钩子
    // 得到Es返回原始对象后 会使用 结果处理钩子,返回钩子定义的对象
    @UseRequestHook("reqHook1")
    @UseResponseHook("respHook1")
    BaseResp<Content> queryRecordByIntensity(ContentSearchParam param);
}

=> 关于高亮:
高亮在同一个系统中定义应该是类似的;
我们可以在配置Bean中调用全局高亮配置类,定义不同的高亮配置

class AutoConfiguration {
    
    void config {
    // 定义
        GlobalEsQueryConfig.configHighLight(DEFAULT_KEY ,() -> SearchSourceBuilder.highlight());
        GlobalEsQueryConfig.configHighLight("html" ,() ->
                SearchSourceBuilder.highlight().fragmentSize(10).numOfFragments(5)
        );
    }
}

可以使用 @HighLight(fields = {"title", "describe"}, highLightKey = "html")
中的 highLightKey 来定义使用的HightLight配置
对于聚合查询的扩展
由于聚合查询的复杂特性,我们通过 访问者模式 实现了 对于 Es聚合查询的封装,将聚合查询结果放入了
org.pippi.elasticsearch.helper.model.resp.AggRes 类中,我们所有 mapper内置方法对于聚合查询的接口 都会放到这个类中;
我们可以通过 json-path的方式快速的获取 聚合结果中的数据例如:

    @Test
    public void aggTest() {
        AggRes aggRes = accountMapper.selectAgg(EsWrappers.lambdaQuery(AccountEntity.class)
                .term(AccountEntity::getGender, "F")
                .agg(AggregationBuilders.terms("_city_distribution").field("city").size(1000)
                        .subAggregation(AggregationBuilders.count("_person_count").field("city"))));
   ==>     System.out.println(JacksonUtils.parseObjToJsonPretty(aggRes.fetchByPath("$._city_distribution.Nogal")));
    }
其中获取 聚合结果可以直接通过 aggRes.fetchByPath(“$._city_distribution.Nogal”) 方式 进行获取。

更多使用方法在仓库中 elasticsearch-hepler-test 中 .

结语

2.0.0尚在完善中,可直接将仓库代码引入项目中,目前项目的es版本为:7.13.3; 理论上是支持 7.*的elasticserch-server;后续会推出更多版本的适配;
关于聚合查询的支持,因为聚合的场景较为复杂,很难通过注解进行合适的描述,因此我们需要在钩子方法中定义查询的聚合行为。
希望这个轮子能为大家带来方便,欢迎多多指出问题和不足,谢谢各位客官。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一些可能包括在大熊猫国家公园门户网站 Mybatis-plus 技术博客中的内容: 1. Mybatis-plus 简介:介绍 Mybatis-plus 的功能、优势等。 2. Mybatis-plus 基本使用:包括如何集成 Mybatis-plus、如何进行 CRUD 操作、如何使用条件构造器、如何使用自定义 SQL 等。 3. Mybatis-plus 高级查询:介绍 Mybatis-plus 的各种高级查询,如 Lambda 表达、QueryWrapper、UpdateWrapper、EntityWrapper 等。 4. Mybatis-plus 分页:介绍 Mybatis-plus 的分页查询、分页插件的使用、自定义分页插件的实现等。 5. Mybatis-plus 乐观锁:介绍 Mybatis-plus 的乐观锁功能、如何使用乐观锁、乐观锁的实现原理等。 6. Mybatis-plus 多租户:介绍 Mybatis-plus 的多租户功能、如何使用多租户、多租户的实现原理等。 7. Mybatis-plus 性能优化:介绍 Mybatis-plus 的性能优化技巧、如何使用分片表、如何使用缓存等。 8. Mybatis-plus 与 Spring Boot 集成:介绍如何将 Mybatis-plus 集成到 Spring Boot 项目中、如何配置 Mybatis-plus、如何使用 Mybatis-plus Starter 等。 9. Mybatis-plus 与其他技术集成:介绍如何将 Mybatis-plus 与其他技术集成,如 Redis、Elasticsearch、ShardingSphere 等。 此外,Mybatis-plus 技术博客也可以包括一些实践经验、案例分析、问题解决过程等内容,以帮助读者更好地理解和使用 Mybatis-plus。在大熊猫国家公园门户网站 Mybatis-plus 技术博客中,可以结合实际项目经验,讲解如何使用 Mybatis-plus 来构建高性能、可扩展的数据访问层。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值