2008-11-26 12 views
10

Estoy trabajando en una aplicación .Net que utiliza Asp.net 3.5 y Lucene.Net Estoy mostrando resultados de búsqueda dados por Lucene.Net en una cuadrícula de datos asp.net. Necesito implementar Paging (10 registros en cada página) para esta página aspx.Paginación usando Lucene.net

¿Cómo puedo hacer esto usando Lucene.Net?

Respuesta

23

Aquí hay una manera de crear una lista simple que coincida con una página específica con Lucene.Net. Esto no es específico de ASP.Net.

int first = 0, last = 9; // TODO: Set first and last to correct values according to page number and size 
Searcher searcher = new IndexSearcher(YourIndexFolder); 
Query query = BuildQuery(); // TODO: Implement BuildQuery 
Hits hits = searcher.Search(query); 
List<Document> results = new List<Document>(); 
for (int i = first; i <= last && i < hits.Length(); i++) 
    results.Add(hits.Doc(i)); 

// results now contains a page of documents matching the query 

Básicamente, la colección Hits es muy liviana. El costo de obtener esta lista es mínimo. Simplemente crea una instancia de los Documentos necesarios al llamar a hits.Doc (i) para compilar su página.

+1

Sugeriría usar algo como Memcache u otro en la memoria de la tienda en el mismo término de búsqueda. De esta forma, no necesita volver a consultar, sino investigar si esto realmente mejora el rendimiento. – bleevo

+0

Siento que a la gente le falta el punto aquí. Creo que el punto aquí es cómo convertir los resultados de Lucene en un formato que funcione bien con la cuadrícula de datos ASP.NET. La cuadrícula de datos ASP.NET está diseñada para funcionar bien con conjuntos de datos .NET ADO (aunque hay otras formas de usarlo). Mi respuesta muestra una forma de convertir objetos Lucene a objetos ADO.NET. Si ignora los detalles de DataGrid, creo que no está respondiendo la pregunta. –

+0

La cuadrícula de datos funciona perfectamente bien con una lista . Simplemente crea la lista a partir de la información contenida en los objetos del documento y DataBind en la cuadrícula. –

-8

Lo que hago es repetir los hits e insertarlos en una tabla temporal en la base de datos. Luego puedo ejecutar una consulta SQL regular, unir esa tabla temporal con otras tablas también y darle a la grilla el DataSet/DataView que quiere.

Tenga en cuenta que hago las inserciones y la consulta en UN VIAJE a la base de datos, porque estoy usando solo un lote SQL.

void Page_Load(Object sender, EventArgs e) 
{ 

    dbutil = new DbUtil(); 
    security = new Security(); 
    security.check_security(dbutil, HttpContext.Current, Security.ANY_USER_OK); 

    Lucene.Net.Search.Query query = null; 

    try 
    { 
     if (string.IsNullOrEmpty(Request["query"])) 
     { 
      throw new Exception("You forgot to enter something to search for..."); 
     } 

     query = MyLucene.parser.Parse(Request["query"]); 

    } 
    catch (Exception e3) 
    { 
     display_exception(e3); 
    } 


    Lucene.Net.Highlight.QueryScorer scorer = new Lucene.Net.Highlight.QueryScorer(query); 
    Lucene.Net.Highlight.Highlighter highlighter = new Lucene.Net.Highlight.Highlighter(MyLucene.formatter, scorer); 
    highlighter.SetTextFragmenter(MyLucene.fragmenter); // new Lucene.Net.Highlight.SimpleFragmenter(400)); 

    StringBuilder sb = new StringBuilder(); 
    string guid = Guid.NewGuid().ToString().Replace("-", ""); 
    Dictionary<string, int> dict_already_seen_ids = new Dictionary<string, int>(); 

    sb.Append(@" 
create table #$GUID 
(
temp_bg_id int, 
temp_bp_id int, 
temp_score float, 
temp_text nvarchar(3000) 
) 
    "); 

    lock (MyLucene.my_lock) 
    { 

     Lucene.Net.Search.Hits hits = null; 
     try 
     { 
      hits = MyLucene.search(query); 
     } 
     catch (Exception e2) 
     { 
      display_exception(e2); 
     } 

     // insert the search results into a temp table which we will join with what's in the database 
     for (int i = 0; i < hits.Length(); i++) 
     { 
      if (dict_already_seen_ids.Count < 100) 
      { 
       Lucene.Net.Documents.Document doc = hits.Doc(i); 
       string bg_id = doc.Get("bg_id"); 
       if (!dict_already_seen_ids.ContainsKey(bg_id)) 
       { 
        dict_already_seen_ids[bg_id] = 1; 
        sb.Append("insert into #"); 
        sb.Append(guid); 
        sb.Append(" values("); 
        sb.Append(bg_id); 
        sb.Append(","); 
        sb.Append(doc.Get("bp_id")); 
        sb.Append(","); 
        //sb.Append(Convert.ToString((hits.Score(i)))); 
        sb.Append(Convert.ToString((hits.Score(i))).Replace(",", ".")); // Somebody said this fixes a bug. Localization issue? 
        sb.Append(",N'"); 

        string raw_text = Server.HtmlEncode(doc.Get("raw_text")); 
        Lucene.Net.Analysis.TokenStream stream = MyLucene.anal.TokenStream("", new System.IO.StringReader(raw_text)); 
        string highlighted_text = highlighter.GetBestFragments(stream, raw_text, 1, "...").Replace("'", "''"); 
        if (highlighted_text == "") // someties the highlighter fails to emit text... 
        { 
         highlighted_text = raw_text.Replace("'","''"); 
        } 
        if (highlighted_text.Length > 3000) 
        { 
         highlighted_text = highlighted_text.Substring(0,3000); 
        } 
        sb.Append(highlighted_text); 
        sb.Append("'"); 
        sb.Append(")\n"); 
       } 
      } 
      else 
      { 
       break; 
      } 
     } 
     //searcher.Close(); 
    } 
+1

Disuadiría esta práctica. Camino a muchas partes móviles. Además, al golpear la base de datos para un tipo de búsqueda de índice de derrotas el propósito. –

+0

@David - Los detalles: My db contiene datos (errores, tickets, problemas) con columnas que cambian con frecuencia. O bien actualizo AMBOS el db Y el índice de Lucene cada vez que estas columnas cambian, O, actualizo SOLO el db. Elegí actualizar solo th db. Otro detalle: la parte de mi aplicación que muestra los resultados ya existía y esperaba un objeto .NET DataSet/DataView como entrada. Por lo tanto, quería traducir los resultados en un DataSet/DataView de todos modos. El OP quiere mostrar los resultados en una cuadrícula de datos que también quiere un DataSet/DataView como entrada. No solo niegues. Sugerir una mejor alternativa. –

+0

La solución que presenté responde a la pregunta de cómo hacer paginación con lucene. Vincular los resultados a una grilla es fácil (ver mi respuesta a su otro comentario). –

Cuestiones relacionadas