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

Why do Postgres full text search and Elasticsearch rank results differently?

我想知道在将 Postgres 的全文搜索与 Elasticsearch 进行比较时,是否有实施全文搜索经验的人可以阐明我的奇怪结果。

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

# 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 更有意义,并且它们在行为上经常相互矛盾。在以下结果中,我列出了每个搜索词返回的前两个 post,或者一个 post 或零(如果仅返回):

Search for:

'apples':

pg: 1. 'I like apples.' 2. 'I like apples and bananas.'

es:

  1. 'I like apples and bananas.'
  2. 'I like apples.'

'bananas':

pg: 1. 'I like bananas.' 2. 'I like apples and bananas.'

es: 1. 'I like bananas.' 2. 'I like apples and bananas.'

'apples and':

pg: 1. 'I like apples.' 2. 'I like apples and bananas.'

es: 1. 'I like apples and bananas.'

'apples and bananas':

pg: 1. 'I like apples and bananas.'

es: 1. 'I like apples and bananas.'

'I like apples.':

pg: 1. 'I like apples.' 2. 'I like apples and bananas.'

es: 1. 'I like apples and bananas.' 2. 'I like apples.'

'app':

pg: no results

es: 1. 'I like apples and bananas.' 2. 'I like apples.'

'appl':

pg: 1. 'I like apples.' 2. 'I like apples and bananas.'

es: 1. 'I like apples and bananas.' 2. 'I like apples.'

我不得不承认,这是默认设置,我没有调整或使用自定义查询语法(执行 AND 与 OR 等)。

您从 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. 我喜欢苹果。
  2. 我喜欢苹果和香蕉。

如果你想弄清楚排名是怎么回事,你可以使用解释:

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

综上所述,您不应期望 postgres 搜索排名与 elasticsearch 排名相匹配。 Elasticsearch 使用归一化的 tf-idf 分数,而 postgres 不考虑文档频率或文档长度。有关详细信息,请参阅此问题:Does PostgreSQL use tf-idf?