2009-11-19 13 views
6

Actualmente estoy tratando de implementar una búsqueda basada en Lucene.NET en una gran base de datos y me he encontrado con un problema tratando de hacer una búsqueda sobre lo que es esencialmente datos relacionales.Almacenamiento de datos relacionales en un índice Lucene.NET

En un nivel alto, los datos que intento buscar están agrupados, cada elemento pertenece a 1 o 3 grupos. Entonces necesito poder hacer una búsqueda de todos los artículos que están en una combinación de grupos (por ejemplo, cada elemento pertenece tanto al grupo A como al grupo B).

Cada una de estas agrupaciones tiene identificadores y descripciones existentes a partir de los datos que estoy buscando, pero las descripciones pueden ser subcadenas (EG: un grupo llamado "Stuff" y el otro "Other stuff"), y no quiero hacer coincidir las categorías que tienen una subcadena de la que estoy buscando.

He estado considerando retirar los datos sin este filtrado y luego filtrar los ID, pero tenía la intención de paginar los datos devueltos por Lucene por razones de rendimiento. También consideré poner las ID en espacios separados y hacer una búsqueda de texto en el campo, pero eso parece un truco total ...

¿Alguien tiene alguna idea de cómo manejar mejor este tipo de búsqueda en Lucene.NET? (Solo para aclarar antes de que alguien diga que estoy usando la herramienta incorrecta, esto es solo un subconjunto de un conjunto de filtros más grande que incluye la búsqueda de texto completo. Si aún crees que estoy usando la herramienta incorrecta, me encantaría escucha cuál es el correcto)

Respuesta

5

He tenido problemas para almacenar datos relacionales i Lucene pero el que tienes debe ser fácil de arreglar.

Supongo que tokenizar los campos del grupo y eso hace que sea posible buscar subcadenas en el valor del campo. Simplemente agregue el campo afectado y debería funcionar como se espera.

Pleasecheckthefollowingsizedetails pequeño trozo de código:

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

El ejemplo agrega dos documentos al índice que son untokenized, hace una búsqueda para la materia y obtiene un hit. Si cambiaste el código para agregarlos tokenizados, entonces tendrás dos hits como ves ahora.

El problema con el uso de Lucene para datos relacionales es que se podría esperar que las búsquedas de comodines y rangos siempre funcionen. Ese no es realmente el caso si el índice es grande debido a la forma en que Lucene resuelve esas consultas.

Otra muestra para ilustrar el comportamiento:

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

Hola HakonB, gracias por la respuesta. He usado el eneldo para algunas otras búsquedas, pero el problema es que un elemento puede estar tanto en "Cosas" como en "Otras cosas" y debe encontrarse al buscar una o ambas. Ejem: A en la materia y otras cosas B en la materia apenas C en tan sólo otras cosas búsqueda para la materia {A, B} Buscar otras cosas {A, C} Buscar cosas y otras cosas { A} – fyjham

+0

He agregado otra muestra que ilustra cómo obtener los resultados correctos, es decir, si te entiendo ahora :-) – HakonB

+1

¡Ah, gracias! Eso parece ser exactamente lo que buscaba. Nunca se me ocurrió que podía agregar 2 campos del mismo nombre a 1 documento. Todavía pensando demasiado como una base de datos relacional típica, supongo =) – fyjham

Cuestiones relacionadas