8.6 SpringBoot集成ElasticSearch之DSL查询

本文介绍了使用DSL查询在Elasticsearch中构建复杂查询,包括BoolQueryBuilder的应用、基本条件定义、不同类型的注解(如@Must、@Should等)及其在Employee查询中的实战示例。还详细讲解了ConstantScore和FunctionScore查询,涉及文档准备、实体映射和高级查询策略。
摘要由CSDN通过智能技术生成

1.简介
(1).DSL查询
为了便于统一设计,所有的查询语句最后都被封装成BoolQueryBuilder,查询条件最终会被封装成为一个有层级关系的对象。查询操作统一由@Search注解来标记,支持分页查询。

(2).基本条件定义
查询条件统一定义成一个POJO对象,对象的属性名即为mapping字段名称,如果属性名称和mapping字段名称不一致,通过@Field注解来映射。属性分为基本类型和对象类型,对象类型会再次递归定义查询条件。

(3).查询语句类型
语句类型通过属性注解来表示,如果属性不加注解,默认是@Must条件,语句支持嵌套,属性详细如下所示。

序号注解说明
1@Must必须满足的条件
2@MustNot必须排除的条件
3@Should可选条件
4@Filter过滤条件
5@Ignore忽略的条件,不参与语句拼装
6@Exists字段是否存在

(4).@Query属性说明

序号属性名默认值说明
1queryTypeQueryType.BOOL默认Bool查询,可选类型:BOOL、FUNCTION_SCORE、CONSTANT_SCORE
2searchTypeSearchType.QUERY_THEN_FETCH默认即可

(5).路由说明
入参实体类实现需RoutingProvider。

2.Bool查询
(1).condition开发
在项目目录“/src/main/java/com/example/es/condition”下新建EmployeeCondition查询条件类,EmployeeCondition类需要实现RoutingProvider接口,具体代码如下。

@Data
public class EmployeeCondition extends SampleEmployeeCondition implements RoutingProvider {
    /**
     * 单范围查询
     */
    @Must
    @Field("age")
    private Range<Integer> ageRange;

    @Override
    public String getRouting() {
        return null;
    }
}

(2).mapper开发
在项目目录“/src/main/java/com/example/es”的EmployeeMapper类中新增分页查询员工信息接口,具体代码如下。

@EasyMapper(indices = "employee", clusterRouter = "sampleCluster")
public interface EmployeeMapper {
    /**
     * 分页查询员工
     *
     * @param pageable          分页信息
     * @param employeeCondition 查询条件
     * @return 员工分页
     */
    @Search(queryType = QueryType.BOOL)
    Page<EmployeeEntity> queryEmployeePage(Pageable pageable, EmployeeCondition employeeCondition);
}

(3).controller开发
在项目目录“/src/main/java/com/example/es”下的EmployeeController类中新增分页查询员工信息接口,具体代码如下。

@RestController
@RequestMapping("/employee")
public class EmployeeController {
    @Resource
    private EmployeeMapper employeeMapper;

    @ResponseBody
    @RequestMapping(value = "/queryEmployeePage", method = RequestMethod.GET)
    public Page<EmployeeEntity> queryEmployeePage() {
        EmployeeCondition employeeCondition = new EmployeeCondition();
        //岗位
        employeeCondition.setJob("Java engineer");

        //年龄范围
        employeeCondition.setAgeRange(Range.of(27, 32).closeLeft());

        //分页
        int page = 0; //页码,从0开始
        int size = 5; //分页大小
        Pageable pageAble = Pageable.of(page, size);
        return employeeMapper.queryEmployeePage(pageAble, employeeCondition);
    }
}

(4).测试
启动项目,然后在postman中请求“http://localhost:8080/employee/queryEmployeePage”,成功后返回对应的信息。

{
    "total": 2,
    "content": [
        {
            "id": "10000001",
            "employeeId": "10000001",
            "name": "James Harden",
            "age": 31,
            "birthday": "1991-01-01",
            "job": "Java engineer",
            "salary": 30000.0
        },
        {
            "id": "10000002",
            "employeeId": "10000002",
            "name": "Stephen Curry",
            "age": 27,
            "birthday": "1995-08-06",
            "job": "Java engineer",
            "salary": 20000.0
        }
    ],
    "pageable": {
        "page": 0,
        "size": 5,
        "offset": 0,
        "from": 0
    },
    "totalPage": 1,
    "empty": false,
    "totalElement": 2
}

(5).DSL语句打印
在项目目录resources下新建ebatis.properties配置文件并添加如下配置。

ebatis.debugEnabled=true
ebatis.clusterRouter=localhost

在application.properties文件中添加如下配置。

logging.level.io.manbang.ebatis = debug

上述查询条件最终会被映射为如下DSL查询语句。

{
  "from" : 0,
  "size" : 2,
  "query" : {
    "bool" : {
      "must" : [ {
        "term" : {
          "job" : {
            "value" : "Java engineer",
            "boost" : 1.0
          }
        }
      }, {
        "range" : {
          "age" : {
            "from" : 27,
            "to" : 32,
            "include_lower" : true,
            "include_upper" : false,
            "boost" : 1.0
          }
        }
      } ],
      "adjust_pure_negative" : true,
      "boost" : 1.0
    }
  },
  "_source" : {
    "includes" : [ "id", "employeeId", "name", "age", "birthday", "job", "salary" ],
    "excludes" : [ ]
  }
}

3.Constant Score查询
(1).文档准备
打开kibana Dev Tools,分别添加索引和文档记录。

PUT /employee
{
	"settings": {
		"number_of_shards": 5,
		"number_of_replicas": 1
	}
}
PUT /employee/_mapping
{
  "properties": {
    "employeeId": {
      "type": "integer"
    },
    "name": {
      "type": "text"
    },
    "age": {
      "type": "integer"
    },
    "birthday": {
      "type": "date",
      "format": "yyyy-MM-dd"
    },
    "job": {
      "type": "keyword"
    },
    "salary": {
      "type": "float"
    },
    "hobby": {
      "type": "text"
    }
  }
}
POST /employee/_doc
{
    "id":"10000001",
    "employeeId":10000001,
	"name": "James Harden",
	"job": "Java engineer",
	"age": 31,
	"salary": 30000.00,
	"birthday": "1991-01-01",
	"hobby":["swimming","running","basketball","football"]
}
{
    "id":"10000002",
	"employeeId":10000002,
	"name": "Stephen Curry",
	"job": "Java engineer",
	"age": 27,
	"salary": 20000.00,
	"birthday": "1995-08-06",
	"hobby":["tennis","football"]
}
{
    "id":"10000003",
    "employeeId":10000003,
	"name": "LeBron James",
	"job": "Technical director",
	"age": 35,
	"salary": 50000.00,
	"birthday": "1987-12-25",
	"hobby":["boxing","climbing","football"]
}
{
    "id":"10000004",
    "employeeId":10000004,
	"name": "Damian Lillard",
	"job": "Vue engineer",
	"age": 25,
	"salary": 18000.00,
	"birthday": "1996-10-01",
	"hobby":["shooting","basketball","football"]
}

(2).entity开发
在项目目录“/src/main/java/com/example/es”的EmployeeEntity类中新增hobby字段,具体代码如下。

@Data
public class EmployeeEntity implements IdProvider{
    @JsonProperty("hobby")
    private List<String> hobby;
}

(3).condition开发
在项目目录“/src/main/java/com/example/es/condition”的EmployeeCondition类中新增hobbyList和hobbyArray字段,EmployeeCondition类需要实现ScoreFunctionProvider接口,具体代码如下。

@Data
public class EmployeeCondition extends SampleEmployeeCondition implements RoutingProvider, ScoreFunctionProvider {
	/**
     * 基本类型集合
     */
    @Field("hobby")
    private List<String> hobbyList;

    /**
     * 基本类型集合
     */
    @Field("hobby")
    private String[] hobbyArray;

    @Override
    public ScoreFunction getFunction() {
        return null;
    }

    @Override
    public ScoreFunctionMode getFunctionMode() {
        return null;
    }
}

(4).mapper开发
在项目目录“/src/main/java/com/example/es”的EmployeeMapper类中新增根据兴趣查询员工信息接口,具体代码如下。

@EasyMapper(indices = "employee", clusterRouter = "sampleCluster")
public interface EmployeeMapper {
    /**
     * 根据兴趣查询员工
     *
     * @param employeeCondition 查询条件
     * @return 员工列表
     */
    @Search(queryType = QueryType.FUNCTION_SCORE)
    List<EmployeeEntity> queryEmployeeList(EmployeeCondition employeeCondition);
}

(5).controller开发
在项目目录“/src/main/java/com/example/es”下的EmployeeController类中新增根据兴趣查询员工信息接口,具体代码如下。

@RestController
@RequestMapping("/employee")
public class EmployeeController {
    @Resource
    private EmployeeMapper employeeMapper;

    @ResponseBody
    @RequestMapping(value = "/queryEmployeeList", method = RequestMethod.GET)
    public List<EmployeeEntity> queryEmployeeList() {
        EmployeeCondition employeeCondition = new EmployeeCondition();
        employeeCondition.setHobbyList(Lists.newArrayList("basketball","football"));
        return employeeMapper.queryEmployeeList(employeeCondition);
    }
}

(6).测试
启动项目,然后在postman中请求“http://localhost:8080/employee/queryEmployeePage”,成功后返回对应的信息。

[
    {
        "id": "10000004",
        "employeeId": "10000004",
        "name": "Damian Lillard",
        "age": 25,
        "birthday": "1996-10-01",
        "job": "Vue engineer",
        "salary": 18000.0,
        "hobby": [
            "shooting",
            "basketball",
            "football"
        ]
    },
    {
        "id": "10000001",
        "employeeId": "10000001",
        "name": "James Harden",
        "age": 31,
        "birthday": "1991-01-01",
        "job": "Java engineer",
        "salary": 30000.0,
        "hobby": [
            "swimming",
            "running",
            "basketball",
            "football"
        ]
    }
]

4.Function Score查询
(1).简介
函数打分查询,允许修改文档的相关度分值,通过提供一个或多个函数来计算查询出来的文档新分值。因此,Function Score查询条件必须要提供打分函数,ebatis要求,条件必须实现ScoreFunctionProvider接口。此接口,有两个接口方法,默认实现getFunction方法即可。

(2).文档准备
打开kibana Dev Tools,分别添加索引和文档记录。

PUT /employee
{
	"settings": {
		"number_of_shards": 5,
		"number_of_replicas": 1
	}
}
PUT /employee/_mapping
{
  "properties": {
    "employeeId": {
      "type": "integer"
    },
    "hobby": {
      "type": "text"
    },
    "name": {
      "type": "text"
    },
    "age": {
      "type": "integer"
    },
    "birthday": {
      "type": "date",
      "format": "yyyy-MM-dd"
    },
    "job": {
      "type": "keyword"
    },
    "salary": {
      "type": "float"
    },
    "profile": {
      "properties": {
        "nickName": {
          "type": "text"
        },
        "avatar": {
          "type": "keyword"
        },
        "grade": {
          "type": "keyword"
        }
      }
    },
    "relative": {
      "properties": {
        "employeeId": {
          "type": "integer"
        }
      }
    }
  }
}
POST /employee/_doc
{
  "id": "10000001",
  "employeeId": 10000001,
  "name": "James Harden",
  "job": "Java engineer",
  "age": 31,
  "salary": 30000.00,
  "birthday": "1991-01-01",
  "hobby": [
    "swimming",
    "running",
    "basketball",
    "football"
  ],
  "profile": {
    "nickName": "squirrel",
    "avatar": "https://www.avatar.com/10000001.png",
    "grade": "diamonds"
  },
  "relative": [
    {
      "employeeId": "10000002"
    },
    {
      "employeeId": "10000004"
    }
  ]
}
{
  "id": "10000002",
  "employeeId": 10000002,
  "name": "Stephen Curry",
  "job": "Java engineer",
  "age": 27,
  "salary": 20000.00,
  "birthday": "1995-08-06",
  "hobby": [
    "tennis",
    "football"
  ],
  "profile": {
    "nickName": "cupid",
    "avatar": "https://www.avatar.com/10000002.png",
    "grade": "golden"
  },
  "relative": [
    {
      "employeeId": "10000001"
    },
    {
      "employeeId": "10000003"
    }
  ]
}
{
  "id": "10000003",
  "employeeId": 10000003,
  "name": "LeBron James",
  "job": "Technical director",
  "age": 35,
  "salary": 50000.00,
  "birthday": "1987-12-25",
  "hobby": [
    "boxing",
    "climbing",
    "football"
  ],
  "profile": {
    "nickName": "mountain",
    "avatar": "https://www.avatar.com/10000003.png",
    "grade": "diamonds"
  },
  "relative": [
    {
      "employeeId": "10000002"
    }
  ]
}
{
  "id": "10000004",
  "employeeId": 10000004,
  "name": "Damian Lillard",
  "job": "Vue engineer",
  "age": 25,
  "salary": 18000.00,
  "birthday": "1996-10-01",
  "hobby": [
    "shooting",
    "basketball",
    "football"
  ],
  "profile": {
    "nickName": "moon",
    "avatar": "https://www.avatar.com/10000004.png",
    "grade": "silver"
  },
  "relative": [
    {
      "employeeId": "10000001"
    }
  ]
}

(3).entity开发
在项目目录“/src/main/java/com/example/es/entity”下新建Profile和Relative类,具体代码如下。

@Data
public class Profile {
    private String nickName;

    private String avatar;

    private String grade;
}
@Data
public class Relative {
    private String employeeId;
}

在项目目录“/src/main/java/com/example/es”的EmployeeEntity类中新增profile和relative字段,具体代码如下。

@Data
public class EmployeeEntity implements IdProvider{
    @JsonProperty("profile")
    private Profile profile;

    @JsonProperty("relative")
    private List<Relative> relativeList;
}

(4).condition开发
在项目目录“/src/main/java/com/example/es/condition”的EmployeeCondition类中新增profileNickName、profileAvatar、profileGrade和relativeEmployeeId字段,getFunction和getFunctionMode方法填充实现逻辑,具体代码如下。

@Data
public class EmployeeCondition extends SampleEmployeeCondition implements RoutingProvider, ScoreFunctionProvider {
	/**
     * 嵌套条件
     */
    @Must
    @Field("profile.nickName")
    private String profileNickName;

    @Must
    @Field("profile.avatar")
    private String profileAvatar;

    @Must
    @Field("profile.grade")
    private String profileGrade;

    /**
     * 非基本类型集合
     */
    @Must
    @Field("relative.employeeId")
    private String relativeEmployeeId;

	@Override
    public ScoreFunction getFunction() {
        return ScoreFunction.fieldValueFactor("age", 10, 10, FieldValueFactorFunction.Modifier.LN);
    }

    @Override
    public ScoreFunctionMode getFunctionMode() {
        return ScoreFunctionMode.of(FunctionScoreQuery.ScoreMode.MAX, CombineFunction.MAX, 1.0f, 1.0f);
    }
}

(5).controller开发
在项目目录“/src/main/java/com/example/es”下的EmployeeController类中修改根据兴趣查询员工信息接口,具体代码如下。

@RestController
@RequestMapping("/employee")
public class EmployeeController {
    @Resource
    private EmployeeMapper employeeMapper;

    @ResponseBody
    @RequestMapping(value = "/queryEmployeeList", method = RequestMethod.GET)
    public List<EmployeeEntity> queryEmployeeList() {
        EmployeeCondition employeeCondition = new EmployeeCondition();
        employeeCondition.setProfileGrade("diamonds");
        employeeCondition.setRelativeEmployeeId("10000004");
        return employeeMapper.queryEmployeeList(employeeCondition);
    }
}

(6).测试
启动项目,然后在postman中请求“http://localhost:8080/employee/queryEmployeePage”,成功后返回对应的信息。

[
    {
        "id": "10000001",
        "employeeId": "10000001",
        "name": "James Harden",
        "age": 31,
        "birthday": "1991-01-01",
        "job": "Java engineer",
        "salary": 30000.0,
        "hobby": [
            "swimming",
            "running",
            "basketball",
            "football"
        ],
        "profile": {
            "nickName": "squirrel",
            "avatar": "https://www.avatar.com/10000001.png",
            "grade": "diamonds"
        },
        "relative": [
            {
                "employeeId": "10000002"
            },
            {
                "employeeId": "10000004"
            }
        ]
    }
]
Elasticsearch 简介 ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。elasticSearch 的使用场景 1、在海量数据前提下,对数据进行检索。比如:京东,淘宝等电商项目课程目标: 1. 了解企业级搜索引擎2. 安装elasticsearch 课程目录: 01 课程介绍02 elasticsearch 简介03 elasticsearch 使用场景04 安装elasticsearch 之前先安装jdk05 安装elasticsearch06 测试elasticsearch是否安装成功 07 安装kibana08 elasticsearch 基本认识 以及添加索引和删除索引09 elasticsearch 添加查询数据10 elasticsearch 修改删除数据11 elasticsearch 有条件的查询12 分词子属性fuzzy查询13 elasticsearch 过滤使用14 elasticsearch 排序与分页15 elasticsearch 如何查询指定的字段16 elasticsearch 高亮显示17 elasticsearch 聚合18 elasticsearch mapping 概念19 elasticsearch 的中文词库20 elasticsearch 中文词库安装测试21 elasticsearch 中文词库的使用案例22 elasticsearch 自定义词库配置23 安装nginx 配置中文词库24 测试elasticsearch 自定义中文词库25 搭建项目父工程26 搭建项目bean-interface-common27 搭建search 的service web 项目28 测试项目是否能与elasticsearch联通29 创建数据库并搭建首页30 数据上传功能的实现类完成31 数据上传控制器完成32 dubbo 介绍以及安装zookeeper33 将数据从mysql 上传到elasticsearch 中34 elasticsearch查询功能分析35 编写业务需求的dsl 语句36 编写输入参数返回结果集的实体类37 实现类编写38 编写实现类中dsl 语句39 返回集结果转换40 结果测试41 测试通过输入查询条件并将数据显示到页面
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值