2016-12-11 13 views
0

Я пытаюсь решить проблему поиска ближайшего соседа. Вот мой код:Lucene scoring: получить подобие косинуса как оценки

// Indexing 
val analyzer = new StandardAnalyzer() 
val directory = new RAMDirectory() 
val config = new IndexWriterConfig(analyzer) 
val iwriter = new IndexWriter(directory, config) 

val queryField = "fieldname" 
stringData.foreach { str => 
    val doc = new Document() 
    doc.add(new TextField(queryField, str, Field.Store.YES)) 
    iwriter.addDocument(doc) 
} 
iwriter.close() 

// Searching 
val ireader = DirectoryReader.open(directory) 
val isearcher = new IndexSearcher(ireader) 

val parser = new QueryParser(queryField, analyzer) 
val query = parser.parse("Some text for testing") 

val hits = isearcher.search(query, 10).scoreDocs 

Когда я смотрю на хитах значения я вижу оценки более 1.

Насколько я знаю, Lucene скоринг формула:

score(q,d) = coord-factor(q,d) · query-boost(q) · cosSim(q,d) · doc-len-norm(d) · doc-boost(d) 

Но Я хочу получить только сходство с косинусом в диапазоне [0,1] между запросом и документом вместо координатного фактора, doc-len-norm и так далее. Каков возможный способ его достижения?

+0

Замечание: эта формула подобия больше не является значением по умолчанию. Начиная с версии 6.0, Lucene по умолчанию использует реализацию [BM25] (https://en.wikipedia.org/wiki/Okapi_BM25). Старое умолчание по-прежнему доступно, см. [Классическое сопоставление] (http://lucene.apache.org/core/6_2_1/core/org/apache/lucene/search/similarities/ClassicSimilarity.html) – femtoRgon

ответ

1

Если вы прошли через это официальное сообщение documentation, вы бы поняли, что остальные термины в выражении score важны и делают процесс подсчета более логичным и согласованным.

Но все же, если вы хотите достичь процесса подсчета очков, используя только Cosine Similaity, тогда вы можете написать свой собственный класс сходства. Я использовал различные методы сходства для поиска документов в моем class assignment. Итак, одним словом, вы можете написать свой собственный метод подобия и присвоить его Lucent's index searcher. Я приводил здесь пример, который вы модифицируете, чтобы выполнить то, что вы хотите.

Напишите свой собственный класс (вам просто нужно переопределить один метод в своем классе).

import org.apache.lucene.search.similarities.BasicStats; 
import org.apache.lucene.search.similarities.SimilarityBase; 

public class MySimilarity extends SimilarityBase { 

    @Override 
    protected float score(BasicStats stats, float termFreq, float docLength) { 
     double tf = 1 + (Math.log(termFreq)/Math.log(2)); 
     double idf = Math.log((stats.getNumberOfDocuments() + 1)/stats.getDocFreq())/Math.log(2); 
     float dotProduct = (float) (tf * idf); 
     return dotProduct; 
    } 

} 

Затем назначьте реализован метод index searcher для расчета релевантности, как показано ниже.

IndexReader reader = DirectoryReader.open(FSDirectory.open(new File(indexPath))); 
IndexSearcher indexSearcher = new IndexSearcher(reader); 
indexSearcher.setSimilarity(new MySimilarity()); 

Здесь я использую продукт tf-idf dot для вычисления сходства между запросом и документами. Формула,

enter image description here

Две вещи должны быть упомянуты здесь:

  • stats.getNumberOfDocuments() возвращает общее количество документов в индексе.
  • stats.getDocFreq() возвращает частоту документа для термина, появляющегося как в запросе, так и в документе.

Lucene теперь вызовет метод score(), который вы внедрили для вычисления оценки релевантности для каждого из согласованных условий; термины, которые удовлетворяют как запросам, так и документам.

Это не прямой ответ на ваш вопрос, который я знаю, но вы можете использовать подход, упомянутый выше, в любом случае. В моем домашнем задании я реализовал 6 различных методов оценки. Надеюсь, это вам тоже поможет.