由ES提供丰富且灵活的查询语言叫做DSL查询(Query DSL)。将查询语句通过http request body发送到ES,主要包含如下参数:
- query符合Query DSL语法的查询语句
- from、size
- timeout
- sort
- 。。。
例如:
GET woniu48/_search{"query": {"term": {"name": "lisi"}}}
基于JSON定义的查询语言,主要包含如下两种类型
- 字段类查询
如term、match、range等,只针对某一个字段进行查询 复合查询
如bool查询等,包含一个或多个字段类查询或则复合查询语句
7.1 字段类查询
字段类查询主要包括以下两类:
全文匹配
- 针对text类型的字段进行全文检索,会对查询语句先进行分词处理,如match、match_phrase等query类型
- 单词匹配
- 不会对查询语句做分词处理,直接匹配字段的倒排索引,如term、terms、range等query类型
全文匹配(Match Query)
GET woniu48/_search{"query": {"match": {"username": "alfred way"}}}
Match Query流程
通过operator参数可以控制单词间的匹配关系,可选项为or或则and
GET woniu48/_search
{
"query": {
"match": {
"desc": {
"query": "非常漂亮",
"operator": "and"
}
}
}
}
上面查询如果分词器分词为“非常”、“漂亮”两个词,查询匹配结果就必须同时包含这两个词的文档
单词匹配(Term Query)
GET woniu48/_search
{
"query": {
"term": {
"name": "lisi"
}
}
}
一次传入多个单词进行查询
GET woniu48/_search
{
"query": {
"terms": {
"name": [
"lisi",
"wangmazi"
]
}
}
}
Range Query(范围查询)
GET woniu48/_search
{
"query": {
"range": {
"age": {
"gte": 20,
"lte": 23
}
}
}
}
7.2 复合查询
复合查询是指包含字段类查询或复合查询的类型,主要包括以下几类:
- constant_score query
- bool query *
- dis_max query
- function_score query
- boosting query
Bool Query
布尔查询由一个或多个布尔子句组成,主要包含如下4个:
| Name | Description |
|---|---|
| filter | 只过滤符合条件的文档,不计算相关性得分 |
| must | 文档必须复合must中的所有条件,会影响相关性得分 |
| must_not | 文档必须不符合must_not中的所有条件 |
| should | 文档可以符合should中的条件,会影响相关性得分 |
FilterFilter查询只过滤符合条件的文档,不会进行相关性算分
- ES针对Filter会有智能缓存,因此其执行效率很高
- 做简单匹配查询且不考虑算分时,推荐使用filter替代query等
GET woniu48/_search { "query": { "bool": { "filter": [ { "term": { "name": "admin" } }, { "range": { "age": { "gte": 25 } } } ] } } }
must
GET woniu48/_search { "query": { "bool": { "must": [ { "match": { "desc": "漂亮的人" } }, { "range": { "age": { "gte": 22 } } } ] } } }must_not
查询描述里面经过分词有“漂亮”一词以及不带“非常”一词的结果GET woniu48/_search { "query": { "bool": { "must": [ { "match": { "desc": "漂亮的人" } } ], "must_not": [ { "match": { "desc": "非常好" } } ] } } }should
只包含should时,文档必须至少满足一个条件(minimun_should_match可以控制满足条件的个数或则百分比)
例如:下面至少满足一个条件GET woniu48/_search { "query": { "bool": { "should": [ { "match": { "desc": "漂亮的人" } }, { "range": { "age": { "lte": 20 } } } ] } } }例如:下面需要满足两个条件
GET woniu48/_search { "query": { "bool": { "should": [ { "match": { "desc": "漂亮的人" } }, { "range": { "age": { "lte": 20 } } } ], "minimum_should_match": 2 } } }同时包含should和must时,文档不必满足should中的条件,但是如果满足条件,会增加相关性得分
该查询只会以must匹配来搜索GET woniu48/_search { "query": { "bool": { "should": [ { "range": { "age": { "lte": 19 } } } ], "must": [ { "match": { "desc": "漂亮的人" } } ] } } }
综合实例
查询年龄大于20并且包含“漂亮的人”描述或则年龄小于18的学员,分页显示第2页,每页显示2条,且按照年龄由低到高排序GET woniu48/_search { "query": { "bool": { "should": [ { "bool": { "must": [ { "match": { "desc": "漂亮的人" } }, { "range": { "age": { "gte": 20 } } } ] } }, { "range": { "age": { "lte": 18 } } } ] } }, "from": 2, "size": 2, "sort": [ { "age": { "order": "desc" } } ] }8 SpringBoot集成
可以通过Spring Data Elasticsearch来进行操作,boot对其进行了集成:
导包
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency>配置连接
spring: elasticsearch: rest: uris: - http://localhost:9200注入模板对象
@Autowired ElasticsearchOperations operations;8.1 对象映射
ES的文档对应于Java的对象,可以通过Spring-Data-Es提供的注解来进行关联:
@Data @Document(indexName = "woniu48") public class Student { @Id @Field(type = FieldType.Integer,name = "id") private Integer id; @Field(type = FieldType.Keyword,name="name") private String name; @Field(type = FieldType.Integer,name="age") private Integer age; @Field(type = FieldType.Text,analyzer = "ik_max_word",name = "desc") private String desc; }
- @Document: 在类级别应用,以指示该类是映射到ES的哪一个Index。最重要的属性是:
- indexName: 用于存储此实体的索引的名称
- @Id: 用来标识ID
- @Field: 在字段级别应用并定义字段的属性:
通过CriteriaQuery条件来查询,可以简单组合条件,不能分词,适用于非常简单的查询
//查询年龄在20-25之间或则名称是"admin"的学员 Criteria c = new Criteria("age").between(20, 25) .or("name").is("admin"); CriteriaQuery cq = new CriteriaQuery(c); SearchHits<Student> shs = operations.search(cq, Student.class); System.out.println(shs.getTotalHits()); shs.getSearchHits().forEach(student -> { System.out.println(student.getContent().getName()+":"+student.getContent().getAge()); });通过StringQuery来查询,直接在java这边构建查询json字符串,不推荐使用
通过NativeSearchQuery来构建复杂查询,包括bool查询等等,推荐使用
/*查询匹配非常漂亮的人或则年龄在90以上的*/ //构建NativeSearchQuery建造器 NativeSearchQueryBuilder nsqb = new NativeSearchQueryBuilder(); //构造Bool查询条件 BoolQueryBuilder bqb = new BoolQueryBuilder(); //通过该Bool查询器构建should查询器 List<QueryBuilder> should = bqb.should(); //向should里面添加两个查询条件 should.add(new MatchQueryBuilder("desc", "非常漂亮的人")); should.add(new RangeQueryBuilder("age").gt(90)); //注册bool查询条件 nsqb.withQuery(bqb); //注册分页(第一页,显示3条) nsqb.withPageable(PageRequest.of(0, 3)); //注册排序(age降序) nsqb.withSort(SortBuilders.fieldSort("age").order(SortOrder.DESC)); //构建NativeSearchQuery NativeSearchQuery nsq = nsqb.build(); //执行查询方法 SearchHits<Student> shs = operations.search(nsq, Student.class); System.out.println(shs.getTotalHits()); shs.getSearchHits().forEach(x -> { Student stu = x.getContent(); System.out.println(stu.getName()+":"+stu.getDesc()+":"+stu.getAge()); });查询结果高亮显示
//创建高亮显示器 HighlightBuilder hb = new HighlightBuilder(); //设置高亮字段 hb.field("desc"); //设置为false,匹配字段都会高亮显示 hb.requireFieldMatch(false); //设置如何高亮显示 hb.preTags("<span style=\"color:red\">"); hb.postTags("</span>"); //设置高亮显示范围以字符为单位 hb.fragmentSize(800); //设置高亮显示的开始位置 hb.numOfFragments(0); NativeSearchQueryBuilder nsqb = new NativeSearchQueryBuilder(); //注册高亮显示器 nsqb.withHighlightBuilder(hb); nsqb.withQuery(new MatchQueryBuilder("desc", "非常漂亮")); NativeSearchQuery nsq = nsqb.build(); SearchHits<Student> shs = operations.search(nsq, Student.class); shs.getSearchHits().forEach(x -> { Student stu = x.getContent(); String desc = stu.getDesc(); //获取高亮显示字段 List<String> hs = x.getHighlightField("desc"); if(hs != null && hs.size() > 0) desc = hs.get(0); System.out.println(stu.getName()+":"+desc); });
