Filtered Query和Post Filter如何选择

在Elasicsearch的官网文档中:(http://www.elastic.co/guide/en/elasticsearch/guide/current/_filtered_query.html),介绍了两种查询方式,一个是Filtered Query,一个是Post Filter。前者是先使用filter,过滤后的结果再query;后者是先query,query的结果再过滤。而在es中,filter的操作使用了cache,速度比query快,因而官网文档提出了一个关于性能的警告(翻译如下): 只有当你需要对搜索结果和聚合使用不同的过滤方式时才考虑使用Post_filter。有时一些用户会直接在常规搜索中使用Post_filter。不要这样做!Post_filter会在查询之后才会被执行,因此会失去过滤在性能上帮助(比如缓存)。Post_filter应该只和聚合一起使用,并且仅当你使用了不同的过滤条件时。

  • 测试一 查询条件:
boolFilter.must(FilterBuilders.termFilter("appId", "R6Z7Ews31c8O4BTidZaWyA"))

目标数:10010077hits,测试结果如下(耗时:ms):

Filtered Query Post Filter
176880 171064
161548 152789
164953 174562
150026 155928
177425 159847

结果分析:对单个查询条件共10010077条目标的查询测试。两者对比发现消耗的时间有大有小,不稳定。且由于Filtered Query第一次查询是没有cache的,该次消耗时间偏大。

  • 测试二 查询条件:
boolFilter.must(FilterBuilders.termFilter("appId", "R6Z7Ews31c8O4BTidZaWyA"));
boolFilter.should(FilterBuilders.termFilter("province", "上海"))
        .should(FilterBuilders.termFilter("province", "山西"))
        .should(FilterBuilders.regexpFilter("city", "14.*"))
        .should(FilterBuilders.regexpFilter("city", "3307.*"))
        .should(FilterBuilders.regexpFilter("city", "40.*"));

目标数:9010477hits,测试结果(单位:ms):

Post Filter Filtered Query
157410 141416
159537 149571
151644 145090
151364 155600

结果分析:此次使用了较为复杂的正则查询,且组合了多种条件。但目标总数与上次差不多,结果对比发现Filtered Query的查询平均速度看起来比使用Post Filter 快了一点但仍不稳定,不能稳定的重现。

  • 测试三 查询条件:
boolFilter.must(FilterBuilders.termFilter("appId", "R6Z7Ews31c8O4BTidZaWyA"))
        .should(FilterBuilders.termFilter("province", "北京"));

目标数:999599hits,测试结果(单位:ms):

Post Filter Filtered Query
24631 19260
25485 21232
25206 20373
23271 19046

结果分析:此次尝试缩小样本量,发现Filtered Query能明显的比Post Filter查询快。快了4、5秒左右,且较为稳定。

  • 测试四 查询条件:
boolFilter.must(FilterBuilders.termFilter("appId", "R6Z7Ews31c8O4BTidZaWyA"))
        .should(FilterBuilders.termFilter("province", "山西"));

目标数:11073hits,测试结果(单位:ms):

Post Filter Filtered Query
1883 547
1563 563
1660 499
1612 604

结果分析:此次样本量缩小至1w+,发现FilteredQuery性能优势更加明显了,比PostFilter快了2到3倍。

  • 测试五 查询条件:
boolFilter.must(FilterBuilders.termFilter("appId", "R6Z7Ews31c8O4BTidZaWyA"))
        .should(FilterBuilders.termFilter("city", "404"));

目标数:1003hits,测试结果(单位:ms):

Post Filter Filtered Query
1616 279
1304 277
1657 302
1339 296

结果分析:此次的目标量只有1003条,两者方式的性能对比最明显,Filtered Query的搜索速度5倍左右于Post Filter 。