SpringBoot整合Easy-Es最佳实践

文章目录

    • [1.1 部署ES和Kibana](#1.1 部署ES和Kibana)
    • [1.2 SpringBoot整合ES及配置](#1.2 SpringBoot整合ES及配置)
      • [1.2.1 引入相关依赖](#1.2.1 引入相关依赖)
      • [1.2.2 YML相关配置](#1.2.2 YML相关配置)
    • [1.3 索引CRUD](#1.3 索引CRUD)
      • [1.3.1 索引托管自动挡](#1.3.1 索引托管自动挡)
        • [1.3.1.1 配置实体模板](#1.3.1.1 配置实体模板)
        • [1.3.1.2 配置启动模式](#1.3.1.2 配置启动模式)
      • [1.3.2 索引手动挡](#1.3.2 索引手动挡)
        • [1.3.2.1 配置启动模式](#1.3.2.1 配置启动模式)
        • [1.3.2.2 配置实体模板](#1.3.2.2 配置实体模板)
        • [1.3.2.3 创建索引](#1.3.2.3 创建索引)
        • [1.3.2.4 查询索引](#1.3.2.4 查询索引)
        • [1.3.2.5 更新索引(不推荐)](#1.3.2.5 更新索引(不推荐))
        • [1.3.2.6 删除索引](#1.3.2.6 删除索引)
    • [1.4 数据CRUD](#1.4 数据CRUD)
      • [1.4.1 数据同步](#1.4.1 数据同步)
      • [1.4.2 数据CRUD](#1.4.2 数据CRUD)
        • [1.4.2.1 新增数据](#1.4.2.1 新增数据)
        • [1.4.2.2 删除数据](#1.4.2.2 删除数据)
        • [1.4.2.3 更新数据(不推荐)](#1.4.2.3 更新数据(不推荐))
        • [1.4.2.4 查询数据(推荐分页查询)](#1.4.2.4 查询数据(推荐分页查询))
      • [1.4.3 嵌套查询](#1.4.3 嵌套查询)
      • [1.4.4 链式调用](#1.4.4 链式调用)
    • [1.5 拓展功能](#1.5 拓展功能)
      • [1.5.1 混合查询](#1.5.1 混合查询)
      • [1.5.2 分页查询](#1.5.2 分页查询)
      • [1.5.3 排序](#1.5.3 排序)
      • [1.5.4 分词 / 模糊匹配](#1.5.4 分词 / 模糊匹配)
      • [1.5.5 条件过滤](#1.5.5 条件过滤)

Easy-Es官网: Easy-Es

1.1 部署ES和Kibana

参考部署ES及配置, 还有配置IK分词器 跳转链接: 部署ES及配置IK分词器

1.2 SpringBoot整合ES及配置

1.2.1 引入相关依赖

java 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-client</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<!--ES相关-->
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.14.0</version>
</dependency>
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-client</artifactId>
    <version>7.14.0</version>
</dependency>
<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>7.14.0</version>
</dependency>
<dependency>
    <groupId>org.dromara.easy-es</groupId>
    <artifactId>easy-es-boot-starter</artifactId>
    <version>2.0.0-beta4</version>
</dependency>

如果出现版本冲突就排除Spring管理的ES依赖

1.2.2 YML相关配置

yaml 复制代码
# Easy-ES配置
easy-es:
  # 是否启动(预先关闭)
  enable: true
  # es连接地址+端口 格式必须为ip:port,如果是集群则可用逗号隔开
  address: 192.168.164.128:9200
  # 如果无账号密码则可不配置此行
  #username:
  # 如果无账号密码则可不配置此行
  #password:
  # 默认为http 可缺省
  schema: http
  # 默认为true 打印banner 若您不期望打印banner,可配置为false
  banner: false
  # 心跳策略时间 单位:ms
  keep-alive-millis: 30000
  # 连接超时时间 单位:ms
  connect-timeout: 5000
  # 通信超时时间 单位:ms
  socket-timeout: 600000
  # 连接请求超时时间 单位:ms
  connection-request-timeout: 5000
  # 最大连接数 单位:个
  max-conn-total: 100
  # 最大连接路由数 单位:个
  max-conn-per-route: 100
  global-config:
    # 索引处理模式,smoothly:平滑模式, not_smoothly:非平滑模式, manual:手动模式,,默认开启此模式
    process-index-mode: manual
    # 开启控制台打印通过本框架生成的DSL语句,默认为开启,测试稳定后的生产环境建议关闭,以提升少量性能
    print-dsl: true
    # 当前项目是否分布式项目,默认为true,在非手动托管索引模式下,若为分布式项目则会获取分布式锁,非分布式项目只需synchronized锁.
    distributed: false
    # 重建索引超时时间 单位小时,默认72H 可根据ES中存储的数据量调整
    reindexTimeOutHours: 72
    # 异步处理索引是否阻塞主线程 默认阻塞 数据量过大时调整为非阻塞异步进行 项目启动更快
    async-process-index-blocking: true
    db-config:
      # 是否开启下划线转驼峰 默认为false
      map-underscore-to-camel-case: true
      # 索引前缀,可用于区分环境  默认为空 用法和MP的tablePrefix一样的作用和用法
#     index-prefix: template_
      # id生成策略 customize为自定义,id值由用户生成,比如取MySQL中的数据id,如缺省此项配置,则id默认策略为es自动生成
      id-type: customize
      # 数据刷新策略,默认为不刷新,若对数据时效性要求比较高,可以调整为immediate,但性能损耗高,也可以调整为折中的wait_until
#     refresh-policy: immediate

1.3 索引CRUD

1.3.1 索引托管自动挡

1.3.1.1 配置实体模板
java 复制代码
@Data
@IndexName(shardsNum = 3,replicasNum = 2) // 可指定分片数,副本数,若缺省则默认均为1
public class Document {
    /**
     * es中的唯一id,如果你想自定义es中的id为你提供的id,比如MySQL中的id,请将注解中的type指定为customize,如此id便支持任意数据类型)
     */
    @IndexId(type = IdType.CUSTOMIZE)
    private Long id;
    /**
     * 文档标题,不指定类型默认被创建为keyword_text类型,可进行精确查询
     */
    private String title;
    /**
     * 文档内容,指定了类型及存储/查询分词器
     */
    @HighLight(mappingField="highlightContent")
    @IndexField(fieldType = FieldType.TEXT, analyzer = Analyzer.IK_SMART, searchAnalyzer = Analyzer.IK_MAX_WORD)
    private String content;
    /**
     * 作者 加@TableField注解,并指明strategy = FieldStrategy.NOT_EMPTY 表示更新的时候的策略为 创建者不为空字符串时才更新
     */
    @IndexField(strategy = FieldStrategy.NOT_EMPTY)
    private String creator;
    /**
     * 创建时间
     */
    @IndexField(fieldType = FieldType.DATE, dateFormat = "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis")
    private String gmtCreate;
    /**
     * es中实际不存在的字段,但模型中加了,为了不和es映射,可以在此类型字段上加上 注解@TableField,并指明exist=false
     */
    @IndexField(exist = false)
    private String notExistsField;
    /**
     * 地理位置经纬度坐标 例如: "40.13933715136454,116.63441990026217"
     */
    @IndexField(fieldType = FieldType.GEO_POINT)
    private String location;
    /**
     * 图形(例如圆心,矩形)
     */
    @IndexField(fieldType = FieldType.GEO_SHAPE)
    private String geoLocation;
    /**
     * 自定义字段名称
     */
    @IndexField(value = "wu-la")
    private String customField;

    /**
     * 高亮返回值被映射的字段
     */
    private String highlightContent;
}
1.3.1.2 配置启动模式
yaml 复制代码
easy-es:
  socketTimeout: 600000 # 请求通信超时时间 单位:ms 默认值600000ms 在平滑模式下,由于要迁移数据,用户可根据数据量大小调整此参数值大小,否则请求容易超时导致索引托管失败,建议您尽量给大不给小,跟那玩意一样,大点没事,太小你懂的!
  global-config:
    process_index_mode: smoothly #smoothly:平滑模式, not_smoothly:非平滑模式, manual:手动模式
    async-process-index-blocking: true # 异步处理索引是否阻塞主线程 默认阻塞
    distributed: false # 项目是否分布式环境部署,默认为true, 如果是单机运行可填false,将不加分布式锁,效率更高.
    reindexTimeOutHours: 72 # 重建索引超时时间 单位小时,默认72H 根据迁移索引数据量大小灵活指定

索引托管自动挡无需考虑索引的问题, 会根据模板类自动更新索引库

若依框架不适配Easy-Es, 无法使用索引自动托管, 只能使用手动挡创建索引

1.3.2 索引手动挡

1.3.2.1 配置启动模式
yaml 复制代码
easy-es:
  global-config:
    process_index_mode: manual # 手动挡模式
1.3.2.2 配置实体模板
java 复制代码
/**
 * 实体类信息
**/
@Data
@IndexName(shardsNum = 3, replicasNum = 2, keepGlobalPrefix = true)
public class Document {
    /**
     * es中的唯一id,如果你想自定义es中的id为你提供的id,比如MySQL中的id,请将注解中的type指定为customize或直接在全局配置文件中指定,如此id便支持任意数据类型)
     */
    @IndexId(type = IdType.CUSTOMIZE)
    private String id;
    /**
     * 文档标题,不指定类型默认被创建为keyword类型,可进行精确查询
     */
    private String title;
    /**
     * 文档内容,指定了类型及存储/查询分词器
     */
    @HighLight(mappingField = "highlightContent")
    @IndexField(fieldType = FieldType.TEXT, analyzer = Analyzer.IK_SMART, searchAnalyzer = Analyzer.IK_MAX_WORD)
    private String content;
    // 省略其它字段...
}
1.3.2.3 创建索引
java 复制代码
/**
 * 方式1
 */
@Test
public void testCreateIndexByEntity() {
    // 绝大多数场景推荐使用 简单至上
    documentMapper.createIndex();
}

/**
 * 方式2
 */
@Test
public void testCreateIndexByEntity() {
    // 适用于定时任务按日期创建索引场景
    String indexName = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
    documentMapper.createIndex(indexName);
}
/**
 * 方式3
 */
@Test
public void testCreateIndex() {
    // 复杂场景使用
    LambdaEsIndexWrapper<Document> wrapper = new LambdaEsIndexWrapper<>();
    // 此处简单起见 索引名称须保持和实体类名称一致,字母小写 后面章节会教大家更如何灵活配置和使用索引
    wrapper.indexName(Document.class.getSimpleName().toLowerCase());
    // 此处将文章标题映射为keyword类型(不支持分词),文档内容映射为text类型(支持分词查询)
    wrapper.mapping(Document::getTitle, FieldType.KEYWORD, 2.0f)
            .mapping(Document::getLocation, FieldType.GEO_POINT)
            .mapping(Document::getGeoLocation, FieldType.GEO_SHAPE)
            .mapping(Document::getContent, FieldType.TEXT, Analyzer.IK_SMART, Analyzer.IK_MAX_WORD);
    // 0.9.8+版本,增加对符串字段名称的支持,Document实体中须在对应字段上加上@Tablefield(value="wu-la")用于映射此字段值
    wrapper.mapping("wu-la", FieldType.TEXT, Analyzer.IK_MAX_WORD, Analyzer.IK_MAX_WORD);
    // 设置分片及副本信息,可缺省
    wrapper.settings(3, 2);
    // 设置别名信息,可缺省
    String aliasName = "daily";
    wrapper.createAlias(aliasName);
    // 设置父子信息,若无父子文档关系则无需设置, 可缺省
    wrapper.join("joinField", "document", "comment");
    // 创建索引
    boolean isOk = documentMapper.createIndex(wrapper);
    Assertions.assertTrue(isOk);
}
1.3.2.4 查询索引
java 复制代码
@Test
public void testExistsIndex() {
    // 测试是否存在指定名称的索引
    String indexName = Document.class.getSimpleName().toLowerCase();
    boolean existsIndex = documentMapper.existsIndex(indexName);
    Assertions.assertTrue(existsIndex);
}
@Test
public void testGetIndex() {
    GetIndexResponse indexResponse = documentMapper.getIndex();
    // 这里打印下索引结构信息 其它分片等信息皆可从indexResponse中取
    indexResponse.getMappings().forEach((k, v) -> System.out.println(v.getSourceAsMap()));
}
1.3.2.5 更新索引(不推荐)
java 复制代码
@Test
public void testUpdateIndex() {
    // 测试更新索引
    LambdaEsIndexWrapper<Document> wrapper = new LambdaEsIndexWrapper<>();
    // 指定要更新哪个索引
    String indexName = Document.class.getSimpleName().toLowerCase();
    wrapper.indexName(indexName);
    wrapper.mapping(Document::getCreator, FieldType.KEYWORD);
    wrapper.mapping(Document::getGmtCreate, FieldType.DATE);
    boolean isOk = documentMapper.updateIndex(wrapper);
    Assertions.assertTrue(isOk);
}
1.3.2.6 删除索引
java 复制代码
@Test
public void testDeleteIndex() {
    // 指定要删除哪个索引
    String indexName = Document.class.getSimpleName().toLowerCase();
    boolean isOk = documentMapper.deleteIndex(indexName);
    Assertions.assertTrue(isOk);
}

1.4 数据CRUD

1.4.1 数据同步

参考RestClient操作, 使用MQ做异步通知来同步MYSQLES的数据

跳转链接: RestClient操作

1.4.2 数据CRUD

1.4.2.1 新增数据
java 复制代码
// 插入一条记录,默认插入至当前mapper对应的索引
Integer insert(T entity);
// 插入一条记录 可指定具体插入的索引,多个用逗号隔开
Integer insert(T entity, String... indexNames);

// 批量插入多条记录
Integer insertBatch(Collection<T> entityList)
// 批量插入多条记录 可指定具体插入的索引,多个用逗号隔开 
Integer insertBatch(Collection<T> entityList, String... indexNames);
  • 如果您在insert时传入的entity有id并且该id对应数据已存在,则此次insert实际效果为更新该id对应的数据,并且更新不计入insert接口最后返回的成功总条数.
  • 当insert接口如上所述,触发了数据更新逻辑,本次更新字段和全局配置的策略(如NOT_NULL/NOT_EMPTY)等均不生效,若您期望策略生效,可以调用update接口而非insert接口.
  • 插入后如需id值可直接从entity中取,用法和MP中一致,批量插入亦可直接从原对象中获取插入成功后的数据id,以上接口返回Integer为成功条数.
1.4.2.2 删除数据
java 复制代码
// 根据 ID 删除
Integer deleteById(Serializable id);
// 根据 ID 删除 可指定具体的索引,多个用逗号隔开 
Integer deleteById(Serializable id, String... indexNames);

// 根据 entity 条件,删除记录
Integer delete(LambdaEsQueryWrapper<T> wrapper);

// 删除(根据ID 批量删除)
Integer deleteBatchIds(Collection<? extends Serializable> idList);
// 删除(根据ID 批量删除)可指定具体的索引,多个用逗号隔开 
Integer deleteBatchIds(Collection<? extends Serializable> idList, String... indexNames);
1.4.2.3 更新数据(不推荐)

在传入的entity中带上id, 可以和新增使用同一份接口, 省事~

java 复制代码
//根据 ID 更新
Integer updateById(T entity);
//根据 ID 更新 可指定具体的索引,多个用逗号隔开 
Integer updateById(T entity, String... indexNames);

// 根据ID 批量更新
Integer updateBatchByIds(Collection<T> entityList);
//根据 ID 批量更新 可指定具体的索引,多个用逗号隔开 
Integer updateBatchByIds(Collection<T> entityList, String... indexNames);

// 根据动态条件 更新记录
Integer update(T entity, LambdaEsUpdateWrapper<T> updateWrapper);
1.4.2.4 查询数据(推荐分页查询)
java 复制代码
// 获取总数
Long selectCount(LambdaEsQueryWrapper<T> wrapper);
// 获取总数 distinct为是否去重 若为ture则必须在wrapper中指定去重字段
Long selectCount(Wrapper<T> wrapper, boolean distinct);

// 根据 ID 查询 
T selectById(Serializable id);
// 根据 ID 查询 可指定具体的索引,多个用逗号隔开 
T selectById(Serializable id, String... indexNames);
// 查询(根据ID 批量查询)
List<T> selectBatchIds(Collection<? extends Serializable> idList);
// 查询(根据ID 批量查询)可指定具体的索引,多个用逗号隔开 
List<T> selectBatchIds(Collection<? extends Serializable> idList, String... indexNames);
// 根据动态查询条件,查询一条记录 若存在多条记录 会报错
T selectOne(LambdaEsQueryWrapper<T> wrapper);
// 根据动态查询条件,查询全部记录
List<T> selectList(LambdaEsQueryWrapper<T> wrapper);

1.4.3 嵌套查询

java 复制代码
/**
 * 场景一: 嵌套and的使用 
 */
@Test
public void testNestedAnd() {
    // 下面查询条件等价于MySQL中的 select * from document where star_num in (1, 2) and (title = '老汉' or title = '推*')
    LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
    wrapper.in(Document::getStarNum, 1, 2)
           .and(w -> w.eq(Document::getTitle, "老汉").or().eq(Document::getTitle, "推*"));
    List<Document> documents = documentMapper.selectList(wrapper);
}
/**
 * 场景二: 拼接and的使用 
 */
@Test
public void testAnd(){
    // 下面查询条件等价于MySQL中的 select * from document where title = '老汉' and content like '推*'
    // 拼接and比较特殊,因为使用场景最多,所以条件与条件之间默认就是拼接and,所以可以直接省略,这点和MP是一样的
    LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
    wrapper.eq(Document::getTitle, "老汉")
           .match(Document::getContent, "推*");
    List<Document> documents = documentMapper.selectList(wrapper);
}

/**
 * 场景二: 嵌套or的使用 
 */
@Test
public void testNestedOr() {
    // 下面查询条件等价于MySQL中的 select * from document where star_num = 1 or (title = '老汉' and creator = '糟老头子')
    LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
    wrapper.eq(Document::getStarNum, 1)
            .or(i -> i.eq(Document::getTitle, "老汉").eq(Document::getCreator, "糟老头子"));
    List<Document> documents = documentMapper.selectList(wrapper);
}
/**
 * 场景三: 拼接or的使用 
 */
@Test
public void testOr() {
    // 下面查询条件等价于MySQL中的 select * from document where title = '老汉' or title = '痴汉'
    LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
    wrapper.eq(Document::getTitle, "老汉")
            .or()
            .eq(Document::getTitle, "痴汉");
    List<Document> documents = documentMapper.selectList(wrapper);
}
/**
 * 场景四: 嵌套filter的使用 其实和场景一一样,只不过filter中的条件不计算得分,无法按得分排序,查询性能稍高
 */
@Test
public void testNestedFilter() {
    // 下面查询条件等价于MySQL中的 select * from document where star_num in (1, 2) and (title = '老汉' or title = '推*')
    LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
    wrapper.in(Document::getStarNum, 1, 2)
            .filter(w -> w.eq(Document::getTitle, "老汉").or().eq(Document::getTitle, "推*"));
    List<Document> documents = documentMapper.selectList(wrapper);
}

/**
 * 场景五: 拼接filter的使用 filter中的条件不计算得分,无法按得分排序,查询性能稍高
 */
@Test
public void testFilter() {
    // 下面查询条件等价于MySQL中的 select * from document where title = '老汉'
    LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
    wrapper.filter().eq(Document::getTitle, "老汉");
    List<Document> documents = documentMapper.selectList(wrapper);
}

/**
 * 场景六: 嵌套mustNot的使用 
 */
@Test
public void testNestedNot() {
    // 下面查询条件等价于MySQL中的 select * from document where title = '老汉' and (size != 18 and age != 18)
    LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
    wrapper.eq(Document::getTitle, "老汉")
           .not(i->i.eq(size,18).eq(age,18));
    List<Document> documents = documentMapper.selectList(wrapper);
}

/**
 * 场景六: 拼接not()的使用
 */
@Test
public void testNot() {
    // 下面查询条件等价于MySQL中的 select * from document where title = '老汉' and  size != 18
    LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
    wrapper.eq(Document::getTitle, "老汉")
           .not()
           .eq(size,18);
    List<Document> documents = documentMapper.selectList(wrapper);
}

1.4.4 链式调用

java 复制代码
// 索引链式构造器
LambdaEsIndexChainWrapper<T> lambdaChainIndex(BaseEsMapper<T> baseEsMapper);
// 查询链式构造器
LambdaEsQueryChainWrapper<T> lambdaChainQuery(BaseEsMapper<T> baseEsMapper);
// 更新(含删除)链式构造器
LambdaEsUpdateChainWrapper<T> lambdaChainUpdate(BaseEsMapper<T> baseEsMapper);
java 复制代码
@Test
public void testOne() {
    // 隔壁老汉写的链式调用
    Document document = EsWrappers.lambdaChainQuery(documentMapper).eq(Document::getTitle, "隔壁老汉").one();
}    
@Test
public void testSelectOne() {
    // 隔壁老王写的半吊子链式调用
    LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
    wrapper.eq(Document::getTitle, "隔壁老王")
            .limit(1);
    Document document = documentMapper.selectOne(wrapper);
}

1.5 拓展功能

1.5.1 混合查询

java 复制代码
/**
 * 正确使用姿势0(最实用,最简单,最推荐的使用姿势):EE满足的语法,直接用,不满足的可以构造原生QueryBuilder,然后通过wrapper.mix传入QueryBuilder
 * @since 2.0.0-beta2 2.0.0-beta2才正式引入此方案,此方案为混合查询的最优解决方案,由于QueryBuilder涵盖了ES中全部的查询,所以通过此方案
 * 理论上可以处理任何复杂查询,并且可以和EE提供的四大嵌套类型无缝衔接,彻底简化查询,解放生产力!
 */
@Test
public void testMix0(){
    // 查询标题为老汉,内容匹配 推*,且最小匹配度不低于80%的数据
    // 当前我们提供的开箱即用match并不支持设置最小匹配度,此时就可以自己去构造一个matchQueryBuilder来实现
    LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
    QueryBuilder queryBuilder = QueryBuilders.matchQuery("content", "推*").minimumShouldMatch("80%");
    wrapper.eq(Document::getTitle,"老汉").mix(queryBuilder);
    List<Document> documents = documentMapper.selectList(wrapper);
    System.out.println(documents);
}
/**
 * 混合查询正确使用姿势1: EE提供的功能不支持某些过细粒度的功能,所有查询条件通过原生语法构造,仅利用EE提供的数据解析功能
 */
@Test
public void testMix1() {
    // RestHighLevelClient原生语法
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    searchSourceBuilder.query(QueryBuilders.matchQuery("content", "推*").minimumShouldMatch("80%"));
    // 仅利用EE查询并解析数据功能
    LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
    wrapper.setSearchSourceBuilder(searchSourceBuilder);
    List<Document> documents = documentMapper.selectList(wrapper);
    System.out.println(documents);
}

1.5.2 分页查询

java 复制代码
// 物理分页
EsPageInfo<T> pageQuery(LambdaEsQueryWrapper<T> wrapper, Integer pageNum, Integer pageSize);
java 复制代码
@Test
public void testPageQuery() {
    LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
    wrapper.match(Document::getTitle, "老汉");
    EsPageInfo<Document> documentPageInfo = documentMapper.pageQuery(wrapper,1,10);
    System.out.println(documentPageInfo);
}

1.5.3 排序

java 复制代码
// 降序排列
wrapper.orderByDesc(排序字段,支持多字段)
    
// 升序排列
wrapper.orderByAsc(排序字段,支持多字段)
    
// 根据得分排序(此功能0.9.7+版本支持;不指定SortOrder时默认降序,得分高的在前,支持升序/降序)
wrapper.sortByScore(boolean condition,SortOrder sortOrder)

1.5.4 分词 / 模糊匹配

java 复制代码
@Test
public void testMatch(){
    // 会对输入做分词,只要所有分词中有一个词在内容中有匹配就会查询出该数据,无视分词顺序
    LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
    wrapper.match(Document::getContent,"技术");
    List<Document> documents = documentMapper.selectList(wrapper);
    System.out.println(documents.size());
}    
@Test
public void testMatchPhrase() {
    // 会对输入做分词,但是需要结果中也包含所有的分词,而且顺序要求一样,否则就无法查询出结果
    // 例如es中数据是 技术过硬,如果搜索关键词为过硬技术就无法查询出结果
    LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
    wrapper.matchPhrase(Document::getContent, "技术");
    List<Document> documents = documentMapper.selectList(wrapper);
    System.out.println(documents);
}
@Test
public void testMatchAllQuery() {
    // 查询所有数据,类似mysql select all.
    LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
    wrapper.matchAllQuery();
    List<Document> documents = documentMapper.selectList(wrapper);
    System.out.println(documents);
}
@Test
public void testMultiMatchQuery() {
    // 从多个指定字段中查询包含老王的数据
    LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
    wrapper.multiMatchQuery("老王", Document::getTitle, Document::getContent, Document::getCreator, Document::getCustomField);
    // 其中,默认的Operator为OR,默认的minShouldMatch为60% 这两个参数都可以按需调整,我们api是支持的 例如:
    // 其中AND意味着所有搜索的Token都必须被匹配,OR表示只要有一个Token匹配即可. minShouldMatch 80 表示只查询匹配度大于80%的数据
    // wrapper.multiMatchQuery("老王",Operator.AND,80,Document::getCustomField,Document::getContent);
    List<Document> documents = documentMapper.selectList(wrapper);
    System.out.println(documents.size());
    System.out.println(documents);
}

1.5.5 条件过滤

java 复制代码
/**
 * 场景五: 拼接filter的使用 filter中的条件不计算得分,无法按得分排序,查询性能稍高
 */
@Test
public void testFilter() {
    // 下面查询条件等价于MySQL中的 select * from document where title = '老汉'
    LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
    wrapper.filter().eq(Document::getTitle, "老汉");
    List<Document> documents = documentMapper.selectList(wrapper);
}
相关推荐
用户9083246027318 小时前
Spring AI 1.1.2 + Neo4j:用知识图谱增强 RAG 检索(上篇:图谱构建)
java·spring boot
洛森唛2 天前
ElasticSearch查询语句Query String详解:从入门到精通
后端·elasticsearch
用户8307196840822 天前
Spring Boot 集成 RabbitMQ :8 个最佳实践,杜绝消息丢失与队列阻塞
spring boot·后端·rabbitmq
Java水解2 天前
Spring Boot 视图层与模板引擎
spring boot·后端
Java水解2 天前
一文搞懂 Spring Boot 默认数据库连接池 HikariCP
spring boot·后端
洋洋技术笔记2 天前
Spring Boot Web MVC配置详解
spring boot·后端
洛森唛2 天前
Elasticsearch DSL 查询语法大全:从入门到精通
后端·elasticsearch
初次攀爬者3 天前
Kafka 基础介绍
spring boot·kafka·消息队列
用户8307196840823 天前
spring ai alibaba + nacos +mcp 实现mcp服务负载均衡调用实战
spring boot·spring·mcp
Java水解3 天前
SpringBoot3全栈开发实战:从入门到精通的完整指南
spring boot·后端