Нахождение сходства между двумя документами - PullRequest
1 голос
/ 13 января 2012

Есть ли встроенный алгоритм, чтобы найти сходство между двумя документами в lucene? Когда я прошел класс сходства по умолчанию, он дает результат в результате сравнения запроса и документа.

Я уже проиндексировал свой документ a, использовал анализатор снежного кома, следующим шагом было бы найти сходство между этими двумя документами.

Может кто-нибудь предложить решение?

1 Ответ

0 голосов
/ 22 января 2015

Кажется, нет встроенного алгоритма.Я полагаю, что есть три способа сделать это:

a) Запустите запрос MoreLikeThis для одного из документов.Переберите результаты, проверьте идентификатор документа и получите оценку.Может быть, не очень, вам может понадобиться вернуть много документов для того, который вы хотите быть среди возвращенных.

b) Сходство косинусов: ответы по ссылке, предоставленной Микосом в его комментарии, объясняют, как сходство косинусовможно рассчитать для двух документов.

в) Вычислите свой собственный показатель сходства Lucene.Счет Lucene добавляет несколько факторов к косинусному сходству (http://lucene.apache.org/core/4_2_0/core/org/apache/lucene/search/similarities/TFIDFSimilarity.html).

. Вы можете использовать

DefaultSimilarity ds = new DefaultSimilarity();
SimScorer scorer = ds.simScorer(stats , arc);
scorer.score(otherDocId, freq);

. Вы можете получить параметры, например, через

AtomicReaderContext arc = IndexReader.leaves().get(0);
SimWeight stats = ds.computeWeight(1, collectionStats, termStats);
stats.normalize(1, 1);

, гдев свою очередь, вы можете получить термин stats, используя TermVector для первого из ваших двух документов, и ваш IndexReader для сбора статистики. Чтобы получить параметр freq, используйте

DocsEnum docsEnum = MultiFields.getTermDocsEnum(reader, null, field, term);

, итерируйте документы довы находите идентификатор документа вашего первого документа и делаете

freq = docsEnum.freq();

Обратите внимание, что вам нужно вызывать «scorer.score» для каждого термина (или каждого термина, который вы хотите рассмотреть) в вашем первом документе, иСуммируйте результаты.

В конце, чтобы умножить параметры «queryNorm» и «координировать», вы можете использовать

//sumWeights was computed while iterating over the first termvector
//in the main loop by summing up "stats.getValueForNormalization();"
float queryNorm = ds.queryNorm(sumWeights);
//thisTV and otherTV are termvectors for the two documents.
//overlap can be easily calculated
float coord = ds.coord(overlap, (int) Math.min(thisTV.size(), otherTV.size()));
return coord * queryNorm * score;

Так что это способ, который должен работать.это не элегантно и из-за сложности получения частот терминов (итерирование по DocsEnum для каждого термина), это также не очень эффективно. Я все еще надеюсь, что что-то из этого кому-то поможет:)

...