es ik 多字段查询_SpringBoot使用注解的方式构建Elasticsearch查询语句,实现多条件的复杂查询...

背景&痛点

通过ES进行查询,如果需要新增查询条件,则每次都需要进行硬编码,然后实现对应的查询功能。这样不仅开发工作量大,而且如果有多个不同的索引对象需要进行同样的查询,则需要开发多次,代码复用性不高。

想要解决这个问题,那么就需要一种能够模块化、配置化的解决方案。

解决方案

思路一:配置参数

通过配置参数的方式来配置参数映射、查询方式等,代码读取配置文件,根据配置文件构建查询语句。

优点:可配置化,新增查询字段基本不需要改动代码,除非增加新的查询方式。

缺点:配置文件太多、太复杂,配置文件配置错误将会导致整个查询不可用。

思路二:注解方式

和方案一类似,通过注解的方式来配置参数映射等,然后读取注解,根据注解构建查询语句。

优点:可配置化,代码清晰、明确,可读性高。

缺点:每次新增查询字段都需要改动代码(在指定字段增加注解)

目前只有这两种可以说大同小异的解决思路,不过不喜欢配置文件太多,所以我就选择了第二种思路。

代码实现(Elasticsearch版本6.7.2)

首先需要创建一个查询方式的枚举类,来区分有哪些查询方式,目前只实现了一些常用的查询类型。

源码如下:

package com.lifengdi.search.enums;

/**

* @author 李锋镝

* @date Create at 19:17 2019/8/27

*/

public enum QueryTypeEnum {

/**

* 等于

*/

EQUAL,

/**

* 忽略大小写相等

*/

EQUAL_IGNORE_CASE,

/**

* 范围

*/

RANGE,

/**

* in

*/

IN,

IGNORE,

/**

* 搜索

*/

FULLTEXT,

/**

* 匹配 和q搜索区分开

*/

MATCH,

/**

* 模糊查询

*/

FUZZY,

/**

* and

*/

AND,

/**

* 多个查询字段匹配上一个即符合条件

*/

SHOULD,

/**

* 前缀查询

*/

PREFIX,

;

}

然后开始自定义注解,通过注解来定义字段的查询方式、映射字段、嵌套查询的path以及其他的一些参数;通过@Repeatable注解来声明这是一个重复注解类。

源码如下:

package com.lifengdi.search.annotation;

import com.lifengdi.search.enums.QueryTypeEnum;

import java.lang.annotation.*;

/**

* 定义查询字段的查询方式

* @author 李锋镝

* @date Create at 19:07 2019/8/27

*/

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.FIELD, ElementType.TYPE})

@Repeatable(DefinitionQueryRepeatable.class)

public @interface DefinitionQuery {

/**

* 查询参数

*

* @return 查询字段

*/

String key() default "";

/**

* 查询类型 see{@link QueryTypeEnum}

*

* @return QueryTypeEnum

*/

QueryTypeEnum type() default QueryTypeEnum.EQUAL;

/**

* 范围查询 from后缀

*

* @return from后缀

*/

String fromSuffix() default "From";

/**

* 范围查询 to后缀

*

* @return to后缀

*/

String toSuffix() default "To";

/**

* 多个字段分隔符

*

* @return 分隔符

*/

String separator() default ",";

/**

* 指定对象的哪个字段将应用于查询映射

* 例如:

* 同一个文档下有多个User对象,对象名分别为createdUser、updatedUser,该User对象的属性有name等字段,

* 如果要根据查询createdUser的name来进行查询,

* 则可以这样定义DefinitionQuery:queryField = cName, mapped = createdUser.name

*

* @return 映射的实体的字段路径

*/

String mapped() default "";

/**

* 嵌套查询的path

*

* @return path

*/

String nestedPath() default "";

}

同时定义@DefinitionQueryRepeatable注解,声明这是上边注解的容器注解类,源码如下:

package com.lifengdi.search.annotation;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

/**

* @author 李锋镝

* @date Create at 19:11 2019/8/27

*/

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.FIELD, ElementType.TYPE})

public @interface DefinitionQueryRepeatable {

DefinitionQuery[] value();

}

如何使用注解?

在索引文档中需要查询的字段、对象或者类上面使用即可。

示例源码:

package com.lifengdi.document;

import com.lifengdi.document.store.*;

import com.lifengdi.search.annotation.DefinitionQuery;

import com.lifengdi.search.enums.QueryTypeEnum;

import lombok.Data;

import org.springframework.data.annotation.Id;

import org.springframework.data.elasticsearch.annotations.Document;

import org.springframework.data.elasticsearch.annotations.Field;

import org.springframework.data.elasticsearch.annotations.FieldType;

import java.util.List;

/**

* 门店Document

*

* @author 李锋镝

* @date Create at 19:31 2019/8/22

*/

@Document(indexName = "store", type = "base")

@Data

@DefinitionQuery(key = "page", type = QueryTypeEnum.IGNORE)

@DefinitionQuery(key = "size", type = QueryTypeEnum.IGNORE)

@DefinitionQuery(key = "q", type = QueryTypeEnum.FULLTEXT)

public class StoreDocument {

@Id

@DefinitionQuery(type = QueryTypeEnum.IN)

@DefinitionQuery(key = "id", type = QueryTypeEnum.IN)

@Field(type = FieldType.Keyword)

private String id;

/**

* 基础信息

*/

@Field(type = FieldType.Object)

private StoreBaseInfo baseInfo;

/**

* 标签

*/

@Field(type = FieldType.Nested)

@DefinitionQuery(key = "tagCode", mapped = "tags.key", type = QueryTypeEnum.IN)

@DefinitionQuery(key = "tagValue", mapped = "tags.value", type = QueryTypeEnum.AND)

@DefinitionQuery(key = "_tagValue", mapped = "tags.value", type = QueryTypeEnum.IN)

private List tags;

}

package com.lifengdi.document.store;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;

import com.fasterxml.jackson.databind.annotation.JsonSerialize;

import com.lifengdi.search.annotation.DefinitionQuery;

import com.lifengdi.search.enums.QueryTypeEnum;

import com.lifengdi.serializer.JodaDateTimeDeserializer;

import com.lifengdi.serializer.JodaDateTimeSerializer;

import lombok.Data;

import org.joda.time.DateTime;

import org.springframework.data.elasticsearch.annotations.Field;

import org.springframework.data.elasticsearch.annotations.FieldType;

/**

* 门店基础信息

*

*/

@Data

public class StoreBaseInfo {

/**

* 门店id

*/

@Field(type = FieldType.Keyword)

private String storeId;

/**

* 门店名称

*/

@Field(type = FieldType.Text, analyzer = 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值