Почему два одинаковых документа оцениваются по-разному?
В настоящее время я выясняю жемчужину шины (я также новичок в упругом поиске и люцене) и пробую кое-что попробовать. Мне нужно будет сделать некоторую (возможно, нетривиальную) оценку, поэтому я попытаюсь справиться с этим. Я прочитал все, что мог найти в Интернете о формуле оценки, и пытаюсь сопоставить найденное с объясненным запросом.
Если я правильно читаю цифры, документы с заголовком "foo foo foo foo" имеют другую оценку, что, конечно, не так, как предполагалось. Я предполагаю, что пропускаю шаг во время или после индексации, но я не мог понять.
Ниже мой код. Я не пойду точно так, как предназначен DSL для шин, потому что хочу разобраться - вещи могут выглядеть более утомительными через некоторое время.
require 'tire'
require 'pp'
class Model
INDEX = 'myindex'
TYPE = 'company'
class << self
def delete_index
Tire.index(INDEX) { delete }
end
def create_mapping
Tire.index INDEX do
create mappings: {
TYPE => {
properties: {
title: { type: 'string' }
}
}
}
end
end
def refresh_index
Tire.index INDEX do
refresh
end
end
end
def initialize(attributes = {})
@attributes = attributes.merge(:_id => object_id) #use oid as id, just for testing
end
def _type
TYPE
end
def id
object_id.to_s #convert to string because tire compares to object_id!
end
def index
item = self
Tire.index INDEX do
store item
end
end
def to_indexed_json
@attributes.to_json
end
ENTITIES = [
new(title: "foo foo foo foo"),
new(title: "foo"),
new(title: "bar"),
new(title: "foo bar"),
new(title: "xxx"),
new(title: "foo foo foo foo"),
new(title: "foo foo"),
new(title: "foo bar baz")
]
QUERIES = {
:foo => { query_string: { query: "foo" } },
:all => { match_all: {} }
}
def self.custom_explained_search(q)
Tire.search(Model::INDEX, :wrapper => Model, :explain => true) do |search|
search.query do |query|
query.send :instance_variable_set, :@value, q
end
end
end
end
class Tire::Results::Collection
def explained
@response["hits"]["hits"].map do |hit|
{
"_id" => hit["_id"],
"_explanation" => hit["_explanation"],
"title" => hit["_source"]["title"]
}
end
end
end
Model.delete_index
Model.create_mapping
Model::ENTITIES.each &:index
Model.refresh_index
s = Model.custom_explained_search(Model::QUERIES[:foo])
pp s.results.explained
Результат печати такой:
[{"_id"=>"2169251840",
"_explanation"=>
{"value"=>0.54932046,
"description"=>"fieldWeight(_all:foo in 0), product of:",
"details"=>
[{"value"=>1.4142135,
"description"=>"btq, product of:",
"details"=>
[{"value"=>1.4142135, "description"=>"tf(phraseFreq=2.0)"},
{"value"=>1.0, "description"=>"allPayload(...)"}]},
{"value"=>0.7768564, "description"=>"idf(_all: foo=4)"},
{"value"=>0.5, "description"=>"fieldNorm(field=_all, doc=0)"}]},
"title"=>"foo foo foo foo"},
{"_id"=>"2169251720",
"_explanation"=>
{"value"=>0.54932046,
"description"=>"fieldWeight(_all:foo in 1), product of:",
"details"=>
[{"value"=>0.70710677,
"description"=>"btq, product of:",
"details"=>
[{"value"=>0.70710677, "description"=>"tf(phraseFreq=0.5)"},
{"value"=>1.0, "description"=>"allPayload(...)"}]},
{"value"=>0.7768564, "description"=>"idf(_all: foo=4)"},
{"value"=>1.0, "description"=>"fieldNorm(field=_all, doc=1)"}]},
"title"=>"foo"},
{"_id"=>"2169250520",
"_explanation"=>
{"value"=>0.48553526,
"description"=>"fieldWeight(_all:foo in 2), product of:",
"details"=>
[{"value"=>1.0,
"description"=>"btq, product of:",
"details"=>
[{"value"=>1.0, "description"=>"tf(phraseFreq=1.0)"},
{"value"=>1.0, "description"=>"allPayload(...)"}]},
{"value"=>0.7768564, "description"=>"idf(_all: foo=4)"},
{"value"=>0.625, "description"=>"fieldNorm(field=_all, doc=2)"}]},
"title"=>"foo foo"},
{"_id"=>"2169251320",
"_explanation"=>
{"value"=>0.44194174,
"description"=>"fieldWeight(_all:foo in 1), product of:",
"details"=>
[{"value"=>0.70710677,
"description"=>"btq, product of:",
"details"=>
[{"value"=>0.70710677, "description"=>"tf(phraseFreq=0.5)"},
{"value"=>1.0, "description"=>"allPayload(...)"}]},
{"value"=>1.0, "description"=>"idf(_all: foo=1)"},
{"value"=>0.625, "description"=>"fieldNorm(field=_all, doc=1)"}]},
"title"=>"foo bar"},
{"_id"=>"2169250380",
"_explanation"=>
{"value"=>0.27466023,
"description"=>"fieldWeight(_all:foo in 3), product of:",
"details"=>
[{"value"=>0.70710677,
"description"=>"btq, product of:",
"details"=>
[{"value"=>0.70710677, "description"=>"tf(phraseFreq=0.5)"},
{"value"=>1.0, "description"=>"allPayload(...)"}]},
{"value"=>0.7768564, "description"=>"idf(_all: foo=4)"},
{"value"=>0.5, "description"=>"fieldNorm(field=_all, doc=3)"}]},
"title"=>"foo bar baz"},
{"_id"=>"2169250660",
"_explanation"=>
{"value"=>0.2169777,
"description"=>"fieldWeight(_all:foo in 0), product of:",
"details"=>
[{"value"=>1.4142135,
"description"=>"btq, product of:",
"details"=>
[{"value"=>1.4142135, "description"=>"tf(phraseFreq=2.0)"},
{"value"=>1.0, "description"=>"allPayload(...)"}]},
{"value"=>0.30685282, "description"=>"idf(_all: foo=1)"},
{"value"=>0.5, "description"=>"fieldNorm(field=_all, doc=0)"}]},
"title"=>"foo foo foo foo"}]
Я неправильно читаю цифры? Или неправильное использование шин? Может, просто пропустить какой-то шаг "переиндексации всей коллекции"?
1 ответ
afaik, если явное поле сортировки не определено, по умолчанию используется сортировка (вариант) tf * idf ( http://en.wikipedia.org/wiki/Tf* idf).
Буквально: термин частота * обратная частота документа.
Из википедии:
Частота терминов (количество терминов): количество терминов в данном документе представляет собой просто число раз, когда данный термин появляется в этом документе.
Частота обратных документов - это показатель того, является ли термин общим или редким во всех документах. Его получают путем деления общего количества документов на количество документов, содержащих термин, а затем с помощью логарифма этого фактора.
В этом случае компонент "частота частоты" сортировки, скорее всего, приведет к тому, что "foo foo foo foo" получит более высокий балл, чем другие документы при поиске "foo"
Более того, об эффекте, который вы видите при смене идентификатора: я не уверен, но я предполагаю, что это связано с тем, что ES хранит документы, упорядоченные id
внутренне (я не уверен в этом)...
В этом случае 2 документа, имеющие одинаковую оценку сортировки, будут отсортированы по идентификатору в качестве тай-брейка. Конечно, вы можете определить несколько сортировок, чтобы изменить это поведение (например: sort = sorta + desc, sortb + desc. В этом случае sortb используется в качестве прерывателя связей для всех документов, которые имеют одинаковые баллы на ScoreA)