过滤Filter
在ES中,提供了两种检索方式:
- Query
- Filter
Query查询要将检索出来的所有文档进行相关度分数计算,然后按照分数进行排序,形成最终的检索结果返回。
Filter过滤擅长于在大量文档中检索出符合条件的文档,检索出来的文档不会进行分数计算和排序,直接作为结果返回。
因此,在大量文档中做检索,Filter的检索效率要大大高于Query。
综合两种查询的特点,如果面向大量的文档做检索,最终还要对文档进行相关度排序,那么通常会让Filter先过滤出符合条件的文档作为中间临时结果,然后让Query在中间临时结果上做二次检索,分数计算和排序,最后将检索的结果返回给客户端。
举一个例子,比方说在淘宝想要买一个¥100 ~ ¥300 之间的一个鼠标,那么我先在搜索框中搜索 "电饭煲",然后将价格区间调到¥100 ~ ¥300。如果使用ES实现该检索过程,那么就先用Filter将电饭煲商品过滤出来,再使用Query将电饭煲中¥100 ~ ¥300的电饭锅检索出来并作相关度排序,最终将排序后的结果返回。
过滤的实现
要想在一次查询中既Query又Filter,那么两次检索必须组合在一个bool内。
GET /postilhub/user/_search
{
"query": {
"bool": {
"must": [
{
"term": {
"username": {
"value": "奥里给"
}
}
}
],
"filter": {
"range": {
"age": {
"gte": 20,
"lte": 30
}
}
}
}
}
}
复制代码
上面指令的含义为:在名为postilhub的Index下,名为user的Type下,先Filter过滤出age字段数据大于等于20,小于等于30的Document,然后在之前过滤出的Documents中Query检索出username字段数据中包含 "奥里给" 的所有Document。
注意:
- 以上命令执行时,ES会默认先执行filter,再执行query。
- 当该filter被多次使用时,ES会自动将该filer过滤出的结果做一个缓存,以增加过滤的效率。
常见过滤类型
上面实现的例子是基于范围的过滤,是常见的过滤类型之一。
常见的过滤类型有:
- range filter:基于范围的过滤。
- term filter:基于单个关键词的过滤。
- terms filter:基于多个关键词的过滤。
- exists filter:基于某个字段存在的过滤。
- ids filter:基于多个id的过滤。
1. 关键词过滤
GET /postilhub/user/_search
{
"query": {
"bool": {
"must": [
{
"term": {
"username": {
"value": "奥里给"
}
}
}
],
"filter": {
"term": {
"role": "学生"
}
}
}
}
}
复制代码
上面指令的含义为:在名为postilhub的Index下,名为user的Type下,先Filter过滤出role字段数据是 "学生" 的Document,然后在之前过滤出的Documents中Query检索出username字段数据中包含 "奥里给" 的所有Document。
2. 多关键词过滤
GET /postilhub/user/_search
{
"query": {
"bool": {
"must": [
{
"term": {
"username": {
"value": "奥里给"
}
}
}
],
"filter": {
"terms": {
"intro": [
"努力学习",
"贪图享受"
]
}
}
}
}
}
复制代码
上面指令的含义为:在名为postilhub的Index下,名为user的Type下,先Filter过滤出intro字段数据中包含 "努力学习" 和 "贪图享受" 的Document,然后在之前过滤出的Documents中Query检索出username字段数据中包含 "奥里给" 的所有Document。
3. 存在字段过滤
GET /postilhub/user/_search
{
"query": {
"bool": {
"must": [
{
"term": {
"username": {
"value": "奥里给"
}
}
}
],
"filter": {
"exists": {
"field": "role"
}
}
}
}
}
复制代码
上面指令的含义为:在名为postilhub的Index下,名为user的Type下,先Filter过滤出存在role字段的Document,然后在之前过滤出的Documents中Query检索出username字段数据中包含 "奥里给" 的所有Document。
4. 多id过滤
GET /postilhub/user/_search
{
"query": {
"bool": {
"must": [
{
"term": {
"username": {
"value": "奥里给"
}
}
}
],
"filter": {
"ids": {
"values": [
"1",
"2",
"3"
]
}
}
}
}
}
复制代码
上面指令的含义为:在名为postilhub的Index下,名为user的Type下,先Filter过滤出id字段为 "1", "2","3" 的Document,然后在之前过滤出的Documents中Query检索出username字段数据中包含 "奥里给" 的所有Document。