2015-06-08 11 views
14

Desidero offrire ai miei utenti i risultati più pertinenti e migliori. Ad esempio, premo i record che hanno un titolo importante, descrizione, foto allegate, ecc. Per contesto: i record sono percorsi ciclabili, con punti di riferimento (coordinate) e metadati come foto, recensioni, ecc.Come disabilitare il punteggio/boosting predefinito in Hibernate Search/Lucene?

Ora, Ho indicizzato questi record utilizzando Hibernate e quindi cerco nell'indice utilizzando Lucene in Hibernate Search. A segnare i miei risultati, costruisco query basate sulle proprietà del documento e aumentare la loro (utilizzando boostedTo()) in una shouldBooleanJunction clause:

bj.should(qb.range().onField("descriptionLength").above(3000).createQuery()).boostedTo(3.0f); 
bj.should(qb.range().onField("views.views").above(5000).createQuery()).boostedTo(3.0f);  
bj.should(qb.range().onField("nameLength").above(20).createQuery()).boostedTo(1.0f);  
bj.should(qb.range().onField("picturesLength").above(0).createQuery()).boostedTo(5.0f); 
bj.should(qb.keyword().onField("routePoints.poi.participant").matching("true").createQuery()).boostedTo(10.0f); 

Per cercare di scoring disabilitazione di Lucene, ho ignorato la classe DefaultSimilarity, impostare tutte le confrontando al punteggio 1.0f e attivato tramite Hibernate config:

public class IgnoreScoringSimilarity extends DefaultSimilarity { 
    @Override 
    public float idf(long docFreq, long numDocs) { 
     return 1.0f; 
    } 

    @Override 
    public float tf(float freq) { 
     return 1.0f; 
    } 

    @Override 
    public float coord(int overlap, int maxOverlap) { 
     return 1.0f; 
    } 

    @Override 
    public float lengthNorm(FieldInvertState state) { 
     return 1.0f; 
    } 

    @Override 
    public float queryNorm(float sumOfSquaredWeights) { 
     return 1.0f; 
    } 
} 

Hibernate config:

<property name="hibernate.search.default.similarity" value="com.search.IgnoreScoringSimilarity"/> 

Questo approccio funziona per il 90% delle volte, tuttavia, sto ancora vedendo alcuni risultati strani che sembrano essere fuori luogo. Lo schema che riconosco è che questi percorsi (documenti) sono di dimensioni molto grandi. Una rotta normale ha circa 20-30 punti di rotta, tuttavia questi risultati fuori dal luogo hanno 100-150. Questo mi lascia credere che il punteggio predefinito di Lucene sia ancora in corso (punteggio più alto a causa delle dimensioni del documento).

Sto facendo qualcosa di sbagliato nel disabilitare i punteggi di Lucene? Potrebbe esserci un'altra spiegazione?

+0

Non una risposta, ma una considerazione: non disattiverei il punteggio predefinito di Lucene, ma lavorerei alla fase di indicizzazione. Costruirei un indicizzatore personalizzato per i tuoi documenti che invece imposta una spinta (ridotta) per i documenti di grandi dimensioni; puoi chiamare 'document.setBoost()' sull'indicizzatore per impostare un valore personalizzato, basato sul numero di punti di riferimento, e controllare i risultati. Qualcosa come 'setBoost (100/routepoints_count)', o qualche funzione esponenziale. –

+0

Grazie per il tuo commento! Ma non darebbe ancora una spinta (seppur piccola) alle dimensioni del documento, calcolando il conteggio delle rotte? Questo è quello che non voglio, perché per il nostro sistema di punteggio, non importa se una rotta ha 2 o 200 punti di riferimento, dovrebbe essere valutata solo dai suoi metadati. – Thermometer

+0

Sì, sarebbe, ma dal momento che stai già aumentando i documenti con grandi fattori, non credo che ciò conterebbe molto. Hai davvero bisogno di indicizzare anche i punti di riferimento? Potresti aggiungere uno snippet del tuo indicizzatore per capire il contenuto dell'indice? –

risposta

1

Posso suggerire un altro approccio basato sull'ordinamento dei risultati personalizzato. Puoi leggere a riguardo nello answer. Questa risposta è leggermente superata, quindi ho modificato questo esempio in base a Lucene API 4.10.1. Comparatore

public abstract class CustomComparator extends FieldComparator<Double> { 
    double[] scoring; 
    double bottom; 
    double topValue; 
    private FieldCache.Ints[] currentReaderValues; 
    private String[] fields; 

    protected abstract double getScore(int[] value); 

    public CustomComparator(int hitNum, String[] fields) { 
     this.fields = fields; 
     scoring = new double[hitNum]; 
    } 

    int[] fromReaders(int doc) { 
     int[] result = new int[currentReaderValues.length]; 
     for (int i = 0; i < result.length; i++) { 
      result[i] = currentReaderValues[i].get(doc); 
     } 
     return result; 
    } 

    @Override 
    public int compare(int slot1, int slot2) { 
     return Double.compare(scoring[slot1], scoring[slot2]); 
    } 

    @Override 
    public void setBottom(int slot) { 
     this.bottom = scoring[slot]; 
    } 

    @Override 
    public void setTopValue(Double top) { 
     topValue = top; 
    } 

    @Override 
    public int compareBottom(int doc) throws IOException { 
     double v2 = getScore(fromReaders(doc)); 
     return Double.compare(bottom, v2); 
    } 

    @Override 
    public int compareTop(int doc) throws IOException { 
     double docValue = getScore(fromReaders(doc)); 
     return Double.compare(topValue, docValue); 
    } 

    @Override 
    public void copy(int slot, int doc) throws IOException { 
     scoring[slot] = getScore(fromReaders(doc)); 
    } 

    @Override 
    public FieldComparator<Double> setNextReader(AtomicReaderContext atomicReaderContext) throws IOException { 
     currentReaderValues = new FieldCache.Ints[fields.length]; 
     for (int i = 0; i < fields.length; i++) { 
      currentReaderValues[i] = FieldCache.DEFAULT.getInts(atomicReaderContext.reader(), fields[i], null, false); 
     } 
     return this; 
    } 

    @Override 
    public Double value(int slot) { 
     return scoring[slot]; 
    } 
} 

Esempio di ricerca

public class SortExample { 

    public static void main(String[] args) throws IOException { 

     final String[] fields = new String[]{"descriptionLength", "views.views", "nameLength"}; 

     Sort sort = new Sort(
       new SortField(
         "", 
         new FieldComparatorSource() { 
          public FieldComparator newComparator(String fieldname, int numHits, int sortPos, boolean reversed) throws IOException { 
           return new CustomComparator(numHits, fields) { 
            @Override 
            protected double getScore(int[] value) { 
             int descriptionLength = value[0]; 
             int views = value[1]; 
             int nameLength = value[2]; 
             return -((descriptionLength > 2000.0 ? 5.0 : 0.0) + 
               (views > 5000.0 ? 3.0 : 0.0) + 
               (nameLength > 20.0 ? 1.0 : 0.0)); 
            } 
           }; 
          } 
         } 
       ) 
     ); 

     IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_4_10_4, new StandardAnalyzer()); 
     Directory directory = new RAMDirectory(); 
     IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig); 

     addDoc(indexWriter, "score 0", 1000, 1000, 10); 
     addDoc(indexWriter, "score 5", 3000, 1000, 10); 
     addDoc(indexWriter, "score 3", 1000, 6000, 10); 
     addDoc(indexWriter, "score 1", 1000, 1000, 30); 
     addDoc(indexWriter, "score 4", 1000, 6000, 30); 
     addDoc(indexWriter, "score 6", 5000, 1000, 30); 
     addDoc(indexWriter, "score 9", 5000, 6000, 30); 

     final IndexReader indexReader = DirectoryReader.open(indexWriter, false); 
     IndexSearcher indexSearcher = new IndexSearcher(indexReader); 
     Query query = new TermQuery(new Term("all", "all")); 
     int nDocs = 100; 

     final TopDocs search = indexSearcher.search(query, null, nDocs, sort); 
     System.out.println("Max " + search.scoreDocs.length + " " + search.getMaxScore()); 
     for (ScoreDoc sd : search.scoreDocs) { 
      Document document = indexReader.document(sd.doc); 
      System.out.println(document.getField("name").stringValue()); 
     } 

    } 

    private static void addDoc(IndexWriter indexWriter, String name, int descriptionLength, int views, int nameLength) throws IOException { 
     Document doc = new Document(); 
     doc.add(new TextField("name", name, Field.Store.YES)); 
     doc.add(new TextField("all", "all", Field.Store.YES)); 
     doc.add(new IntField("descriptionLength", descriptionLength, Field.Store.YES)); 
     doc.add(new IntField("views.views", views, Field.Store.YES)); 
     doc.add(new IntField("nameLength", nameLength, Field.Store.YES)); 
     indexWriter.addDocument(doc); 
    } 
} 

Codice sarà in uscita

score 9 
score 6 
score 5 
score 4 
score 3 
score 1 
score 0 
+0

Grazie per il suggerimento! Questo sembra un approccio interessante. Tuttavia, non sono sicuro che ciò funzionerebbe per il modo in cui voglio dare impulso. Sembra che la risposta che hai collegato amplifica solo i campi stessi? In questo modo non posso fare cose come 'boost route con 'isRoundtrip' = false' per x o 'boost route con lunghezza del titolo> 50 per x'. Per favore correggimi se sbaglio! – Thermometer

+0

Invece di aumentare la query, è possibile modificare la formula della classifica nel punteggio. Nell'esempio hai 'campo1 * 0.5 + campo2 * 1.4 + campo3 * 1.8', puoi cambiarlo in' titleLength> 50.0? 3.0: 0.0 + nameLength> 0.0? 1.0: 0.0' e così via. Con questo approccio hai ancora più controllo sulla classifica, perché puoi avere qualsiasi formula di punteggio. –

+0

Interessante, sperimenterò un po 'con questo approccio, grazie per il suggerimento, +1. – Thermometer

-1

Hibernate config:

<property name="hibernate.search.default.similarity" value="com.search.IgnoreScoringSimilarity"/> 

Questo approccio funziona per il 90% del tempo, tuttavia, Sto ancora vedendo qualcosa di strano risultati che sembrano fuori luogo. Lo schema che riconosco è che questi percorsi (documenti) sono di dimensioni molto grandi. Una rotta normale ha circa 20-30 punti di rotta, tuttavia questi risultati fuori dal luogo hanno 100-150. Questo mi porta a credere che il punteggio predefinito di Lucene sia ancora in corso (punteggio più alto a causa delle dimensioni del documento).

+0

I pensi di voler postare qualcos'altro? Questa è una copia della mia domanda. – Thermometer

Problemi correlati