【Elasticsearch】6. Filter过滤

3,001 阅读3分钟

过滤Filter

在ES中,提供了两种检索方式:

  • Query
  • Filter

Query查询要将检索出来的所有文档进行相关度分数计算,然后按照分数进行排序,形成最终的检索结果返回。

Filter过滤擅长于在大量文档中检索出符合条件的文档,检索出来的文档不会进行分数计算和排序,直接作为结果返回。

因此,在大量文档中做检索,Filter的检索效率要大大高于Query

综合两种查询的特点,如果面向大量的文档做检索,最终还要对文档进行相关度排序,那么通常会让Filter先过滤出符合条件的文档作为中间临时结果,然后让Query在中间临时结果上做二次检索,分数计算和排序,最后将检索的结果返回给客户端。

20210817025438.png

举一个例子,比方说在淘宝想要买一个¥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。