2009-11-19 17 views
6

Attualmente sto cercando di attuare una ricerca basata Lucene.NET su un database di grandi dimensioni e ho colpito un intoppo cercando di fare una ricerca su ciò che è essenzialmente dati relazionali.Memorizzazione dati relazionali in un indice Lucene.NET

A un livello elevato i dati che sto cercando di ricerca è raggruppato, ogni elemento appartiene a 1 a 3 gruppi. Devo quindi essere in grado di effettuare una ricerca per tutti gli elementi che si trovano in una combinazione di gruppi (ad esempio: ogni elemento appartiene al gruppo A e al gruppo B).

Ciascuno di questi raggruppamenti ha ID e descrizioni esistenti dai dati che sto cercando, ma le descrizioni possono essere sotto-stringhe l'una dell'altra (EG: un gruppo denominato "Stuff" e l'altro "Altre cose"), e non voglio abbinare le categorie che hanno una sottostringa di quello che sto cercando.

Ho preso in considerazione tirando i dati indietro senza questo filtraggio e poi filtrando le ID, ma io intendevo impaginare i dati restituiti da Lucene per motivi di prestazioni. Ho anche pensato di mettere gli ID in uno spazio separato e facendo un testo di ricerca sul campo, ma che sembra un hack totale ...

Qualcuno ha qualche idea di come gestire al meglio questo tipo di ricerca in Lucene.NET? (Giusto per chiarire prima che qualcuno dica che sto usando lo strumento sbagliato, questo è solo un sottoinsieme di un più ampio set di filtri che include la ricerca full-text. Se pensi ancora che io stia usando lo strumento sbagliato anche se mi piacerebbe ascoltare ciò che quello di destra è)

risposta

5

ho avuto la mia parte di problemi con la memorizzazione dei dati relazionali i Lucene, ma quello che hai dovrebbe essere facile da risolvere.

Credo che si tokenize i campi di gruppo e che rende possibile la ricerca di sottostringhe nel valore del campo. Basta aggiungere il campo askenizzato e dovrebbe funzionare come previsto.

Controllare quanto segue piccolo pezzo di codice:

internal class Program { 
    private static void Main(string[] args) { 
     var directory = new RAMDirectory(); 
     var writer = new IndexWriter(directory, new StandardAnalyzer()); 
     AddDocument(writer, "group", "stuff", Field.Index.UN_TOKENIZED); 
     AddDocument(writer, "group", "other stuff", Field.Index.UN_TOKENIZED); 
     writer.Close(true); 

     var searcher = new IndexSearcher(directory); 
     Hits hits = searcher.Search(new TermQuery(new Term("group", "stuff"))); 

     for (int i = 0; i < hits.Length(); i++) { 
      Console.WriteLine(hits.Doc(i).GetField("group").StringValue()); 
     } 
    } 

    private static void AddDocument(IndexWriter writer, string name, string value, Field.Index index) { 
     var document = new Document(); 
     document.Add(new Field(name, value, Field.Store.YES, index)); 
     writer.AddDocument(document); 
    } 
} 

L'esempio aggiunge due documenti per l'indice che sono untokenized, fa una ricerca per le cose e ottiene un colpo. Se hai modificato il codice per aggiungerli token, avrai due hit come vedi ora.

Il problema con l'utilizzo di Lucene per i dati relazionali è che ci si potrebbe aspettare che le ricerche jolly e la gamma sempre funzionerà. Questo non è il caso se l'indice è grande a causa del modo in cui Lucene risolve queste domande.

Un altro esempio per illustrare il comportamento:

private static void Main(string[] args) { 
     var directory = new RAMDirectory(); 
     var writer = new IndexWriter(directory, new StandardAnalyzer()); 

     var documentA = new Document(); 
     documentA.Add(new Field("name", "A", Field.Store.YES, Field.Index.UN_TOKENIZED)); 
     documentA.Add(new Field("group", "stuff", Field.Store.YES, Field.Index.UN_TOKENIZED)); 
     documentA.Add(new Field("group", "other stuff", Field.Store.YES, Field.Index.UN_TOKENIZED)); 
     writer.AddDocument(documentA); 
     var documentB = new Document(); 
     documentB.Add(new Field("name", "B", Field.Store.YES, Field.Index.UN_TOKENIZED)); 
     documentB.Add(new Field("group", "stuff", Field.Store.YES, Field.Index.UN_TOKENIZED)); 
     writer.AddDocument(documentB); 
     var documentC = new Document(); 
     documentC.Add(new Field("name", "C", Field.Store.YES, Field.Index.UN_TOKENIZED)); 
     documentC.Add(new Field("group", "other stuff", Field.Store.YES, Field.Index.UN_TOKENIZED)); 
     writer.AddDocument(documentC); 

     writer.Close(true); 

     var query1 = new TermQuery(new Term("group", "stuff")); 
     SearchAndDisplay("First sample", directory, query1); 

     var query2 = new TermQuery(new Term("group", "other stuff")); 
     SearchAndDisplay("Second sample", directory, query2); 

     var query3 = new BooleanQuery(); 
     query3.Add(new TermQuery(new Term("group", "stuff")), BooleanClause.Occur.MUST); 
     query3.Add(new TermQuery(new Term("group", "other stuff")), BooleanClause.Occur.MUST); 
     SearchAndDisplay("Third sample", directory, query3); 
    } 

    private static void SearchAndDisplay(string title, Directory directory, Query query3) { 
     var searcher = new IndexSearcher(directory); 
     Hits hits = searcher.Search(query3); 
     Console.WriteLine(title); 
     for (int i = 0; i < hits.Length(); i++) { 
      Console.WriteLine(hits.Doc(i).GetField("name").StringValue()); 
     } 
    } 
+0

Ciao HakonB, grazie per la risposta. Ho usato tokenized per alcune altre ricerche, ma il problema è che un elemento può essere sia in "Stuff" che in "Other Stuff" e deve essere trovato durante la ricerca di uno o entrambi. EG: A in roba e altre cose B in solo roba C in soli altre cose Cerca roba {A, B} Cerca altre cose {A, C} Ricerca per le cose e altre cose { A} – fyjham

+0

Ho aggiunto un altro esempio che illustra come ottenere i risultati corretti, ovvero se ti capisco subito :-) – HakonB

+1

Ah, grazie! Sembra esattamente quello che stavo cercando. Non mi è mai venuto in mente che potrei effettivamente aggiungere 2 campi con lo stesso nome a 1 documento. Penso ancora troppo a un tipico database relazionale suppongo =) – fyjham

Problemi correlati