2009-11-19 14 views
6

Obecnie próbuję wdrożyć wyszukiwanie oparte na Lucene.NET na dużej bazie danych i trafiłem w szkopułę, próbując wyszukać, co jest w istocie danymi relacyjnymi.Przechowywanie danych relacyjnych w indeksie Lucene.NET

Na wysokim poziomie dane, które próbuję wyszukiwać są pogrupowane, każdy element należy do 1 do 3 grup. Następnie muszę mieć możliwość wyszukiwania wszystkich elementów, które są w kombinacji grup (EG: Każda pozycja należy do grupy A i grupy B).

Każda z tych grup ma identyfikatory i opisy istniejące na podstawie danych, których szukam, ale opisy mogą być pod-łańcuchami nawzajem (np .: jedna grupa o nazwie "Rzeczy" i druga "inne rzeczy"), i nie chcę dopasowywać kategorii, które mają podciąg tego, którego szukam.

Zastanawiam się nad odzyskaniem danych bez tego filtrowania, a następnie filtrowania identyfikatorów, ale miałem zamiar stronicować dane zwrócone przez Lucene ze względu na wydajność. Zastanawiałem się również nad umieszczeniem identyfikatorów w oddzielonych spacjami i przeprowadzaniu wyszukiwania tekstowego na polu, ale wygląda na to, że to włamanie ...

Czy ktoś ma pomysł, jak najlepiej radzić sobie z tego rodzaju wyszukiwaniem? Lucene.NET? (Aby wyjaśnić, zanim ktoś powie, że używam niewłaściwego narzędzia, jest to tylko podzbiór większego zestawu filtrów, który obejmuje wyszukiwanie pełnotekstowe. Jeśli nadal uważasz, że używam niewłaściwego narzędzia, chociaż chciałbym usłyszeć, co jest właściwe)

Odpowiedz

5

Mam wiele problemów z przechowywaniem danych relacyjnych i Lucene, ale ta, którą masz, powinna być łatwa do naprawienia.

Domyślam się, że tokenize pól grupy i umożliwia wyszukiwanie podłańcuchów w wartości pola. Po prostu dodaj pole niezsynchronizowane i powinno działać tak, jak powinno.

Proszę sprawdzić poniższy kawałek kodu:

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); 
    } 
} 

Próbka dodaje dwa dokumenty do indeksu, które są untokenized, nie szukaj na rzeczy i dostaje jedno trafienie. Jeśli zmienisz kod, aby dodać je tokenized, będziesz miał dwa trafienia, jak widać teraz.

Problem z używaniem Lucene do relacyjnych danych jest taki, że można oczekiwać, że wyszukiwanie za pomocą symboli wieloznacznych i zakresów zawsze będzie działać. Tak naprawdę nie jest, jeśli indeks jest duży ze względu na sposób, w jaki Lucene rozwiązuje te zapytania.

Inną próbkę do zilustrowania problemu:

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

Hi HakonB, dzięki za odpowiedź. Użyłem nieokreślonego dla kilku innych wyszukiwań, ale problem polega na tym, że jeden element może znajdować się zarówno w "Rzeczy", jak i "Inne rzeczy" i musi zostać znaleziony podczas wyszukiwania jednego lub obu. EG: A na rzeczy i inne rzeczy B w tylko rzeczy C w ciągu zaledwie inne rzeczy Szukaj rzeczy {A, B} Szukaj innych rzeczy {A, C} Search na rzeczy i inne rzeczy { A} – fyjham

+0

Dodałem kolejną próbkę, która ilustruje, jak uzyskać poprawne wyniki - to znaczy, jeśli rozumiem cię teraz :-) – HakonB

+1

Ah, dzięki! Wydaje mi się, że dokładnie to, czego szukałem. Nigdy nie przyszło mi do głowy, że mogę dodać 2 pola o tej samej nazwie do 1 dokumentu. Nadal myślę za bardzo jak typowa relacyjna baza danych, którą zgaduję =) – fyjham

Powiązane problemy