代码之家  ›  专栏  ›  技术社区  ›  Matt Welke

为什么Postgres全文搜索和Elasticsearch对结果的排名不同?

  •  3
  • Matt Welke  · 技术社区  · 7 年前

    我使用一对Rails应用程序来测试它们,每个应用程序都有相同的模型(但有不同的gem,pg测试使用“textacular”,es测试使用“searchkick”)和相同的测试数据:

    # seeds.rb
    
    def make_post(body)
      {
        title: 'A Post About Fruits',
        body: body,
        num_likes: 0
      }
    end
    
    Post.destroy_all
    
    Post.create([
      make_post('I like apples.'),
      make_post('I like bananas.'),
      make_post('I like apples and bananas.'),
      make_post('I like oranges.'),
      make_post('I like.')
    ])
    

    但当我在他们身上运行一系列搜索时,结果有时似乎对Postgres更有意义,有时对Elasticsearch更有意义,而且他们在行为上经常相互矛盾。在下面的结果中,我列出了每个搜索词返回的前两个帖子,或者一个帖子或零,如果这就是返回的全部内容:

    “苹果”:

    “我喜欢苹果。” 2.“我喜欢苹果和香蕉。”

    1. “我喜欢苹果和香蕉。”
    2. “我喜欢苹果。”

    第页: “我喜欢香蕉。” 2.“我喜欢苹果和香蕉。”

    “我喜欢香蕉。”

    “苹果和”:

    “我喜欢苹果。” 2.“我喜欢苹果和香蕉。”

    “我喜欢苹果和香蕉。”

    “苹果和香蕉”:

    “我喜欢苹果和香蕉。”

    “我喜欢苹果和香蕉。”

    “我喜欢苹果。”:

    第页: 2.“我喜欢苹果和香蕉。”

    锿: 2.“我喜欢苹果。”

    pg:无结果

    “我喜欢苹果和香蕉。” 2.“我喜欢苹果。”

    “我喜欢苹果。”

    “我喜欢苹果和香蕉。”

    我必须承认,这是默认设置,我没有调优或使用自定义查询语法(to do和vs等)。

    1 回复  |  直到 7 年前
        1
  •  3
  •   dshockley    7 年前

    你从Elasticsearch得到了奇怪的结果,因为一些统计数据是跨单个碎片计算的,而不是跨整个索引。通常这很好,因为大多数文档集合都很大,但当一个碎片中只有少数文档时,这些统计数据就没有多大意义。在你的例子中,我认为有问题的统计数据是avgFieldLength,它有助于tfNorm分数。尝试仅使用一个碎片创建新索引:

    PUT /testindex
    {
      "settings": {
        "index": {
          "number_of_shards": 1
        }
      }
    }
    
    
    POST /testindex/doc/1
    {
      "body": "I like apples."
    }
    
    
    POST /testindex/doc/2
    {
      "body": "I like apples and bananas."
    }
    

    然后查询:

    POST /testindex
    {
      "query": {
        "query_string": {
          "query": "apples"
        }
     }
    

    1. 我喜欢苹果。

    如果您想了解排名情况,可以使用解释:

    POST /testindex
    {
      "explain": true,
      "query": {
        "query_string": {
          "query": "apples"
        }
     }
    

    尽管如此,你不应该期望postgres的搜索排名与elasticsearch的排名相匹配。Elasticsearch使用归一化tf idf分数,postgres不考虑文档频率或文档长度。有关更多信息,请参阅此问题: Does PostgreSQL use tf-idf?