ElasticSearch 高亮显示大文档搜索结果的策略和性能对比(译)

2016年12月,咱们开始研究Ambar——一个文档搜索系统。Ambar使用ElasticSearch做为核心搜索引擎。面试

在Ambar开发的过程当中,咱们处理了不少与ES相关的问题,咱们想分享咱们获得的宝贵经验。让咱们从每一个搜索系统的一个重要功能开始——高亮显示搜索结果。算法

在任何搜索系统的可用性中,适当的结果高亮显示是最有价值的部分,首先,它为用户提供了关于内部搜索逻辑的必要信息,以及为何显示该结果。此外,它也使咱们可以仅仅经过快速浏览重点而不是下载和浏览整个文档来估计结果。api

由于Ambar是一个文档搜索系统,我说的文档也是指文件,因此它必须处理很是大的文件(就全文搜索而言),大小大于100Mb。本文介绍了在利用ElasticSearch高亮显示大型文档时如何达到高性能。app

定义问题

Ambar使用ES做为搜索引擎,搜索通过解析的文件/文档内容及其元数据。下面是Ambar在ES中存储一个文档的例子:elasticsearch

{
    sha256: "1a4ad2c5469090928a318a4d9e4f3b21cf1451c7fdc602480e48678282ced02c",
    meta: [
        {
            id: "21264f64460498d2d3a7ab4e1d8550e4b58c0469744005cd226d431d7a5828d0",
            short_name: "quarter.pdf",
            full_name: "//winserver/store/reports/quarter.pdf",
            source_id: "crReports",
            extension: ".pdf",
            created_datetime: "2017-01-14 14:49:36.788",
            updated_datetime: "2017-01-14 14:49:37.140",
            extra: [],
            indexed_datetime: "2017-01-16 18:32:03.712"
        }
    ],
    content: {
        size: 112387192,
        indexed_datetime: "2017-01-16 18:32:33.321",
        author: "John Smith",
        processed_datetime: "2017-01-16 18:32:33.321",
        length: "",
        language: "",
        state: "processed",
        title: "Quarter Report (Q4Y2016)",
        type: "application/pdf",
        text: ".... laaaaaarge text here ...."
    }
}

上面的JSON文档是一个解析后的.pdf文件,里面有财务报告,文件大小约为100Mb。content.text字段包含报告的解析文本,其大小也约为100Mb。分布式

让咱们作一个简单的实验。索引1000个文档,如我之前指定的文档,而不定义任何索引调优或自定义映射。而后看看ES会多快地搜索它们,并高亮显示content.text字段中的检索关键字。ide

结果以下:性能

  • 在content.text字段中进行match_phrase搜索会耗费5-30秒
  • 突出显示content.text字段中的文本内容,每次命中平均须要10秒

这种结果是不能接受的。任何使用搜索系统的用户都但愿在点击“搜索”按钮后当即获得搜索结果,而不须要等待半分钟就会出现第一个结果。让咱们来看看高亮显示这个缓慢突出的问题并解决它。测试

选择高亮策略

ES 和 Lucene底层有三种高亮策略可供选择,这是官方文档连接,三种策略以下:

  • Plain - ES中默认的高亮显示,它是最慢的,但它作了最精确的高亮显示,几乎彻底匹配Lucene的搜索逻辑。要高亮显示检索关键字,它必须将整个文档加载到内存中并从新分析它。
  • Postings - 更快的一个。它将文档的字段分割成句子,并使用BM25算法对匹配的结果进行标记,从而对结果进行排序,但它须要在索引中额外存储句子的位置。
  • Fast Vector Highlighting (FVH) - 彷佛是最快的,特别是对于大型文档。须要为索引中的每一个令牌存储位置偏移量。在本例中,要对检索词进行高亮显示,它不须要检索整个文档,只需检索接近命中的令牌,因为每一个令牌的位置是已知的,所以这个速度很是快。

所以,如今你能够猜到为何ES能够开箱即用地对大文档中的检索关键字高亮显示。对于每次命中检索整个文档并从新分析它的性能很是昂贵,尤为是对于大于1Mb的文档。

因为咱们绝对不能使用普通的高亮显示方式,咱们测试了Postings和FVH。最后的选择是FVH,缘由以下:

  • 若是使用FVH,一个100Mb的文档高亮显示大约须要10-20毫秒,Postings大约须要一秒钟
  • Postings并不老是正确地将文档的字段划分为句子,这就是为何高亮显示的大小会有很大的差别(在某些状况下,从50个单词到数千个单词)。FVH没有这种问题,由于它检索固定数量的令牌,而不是句子。
  • Postings以任何顺序突出显示令牌,在复杂查询中不能正常工做。对于引用,它不会正确地突出显示具备指定slop值的match_phrase查询的结果。它将把它解释为bool查询,高亮显示整个文档字段中的每一个匹配令牌。

在FVH测试中,咱们发现了一个很是棘手的问题。它确实解释了match_phrase查询,而不是Lucene的搜索。它只按查询中指定的顺序突出显示令牌,但Lucene的搜索将令牌按任意顺序解释为命中。若是您正在搜索“John Smith”短语,可是文档在其字段中有“Smith John”值,ES将检索该文档做为命中结果,但FVH不会高亮显示它。解决这个问题的办法是短语置换。咱们提交不一样的查询以搜索和高亮显示,Search获取默认查询,高亮显示经过修改源短语中全部单词位置的变化而构建查询。

总结

ES实际上能够处理大型文档,而且仍然可以提供至关好的性能,重要的是正确地设置索引并记住全部与ES相关的问题。

编译自:Highlighting Large Documents in ElasticSearch