Lucene es un motor de búsqueda eficaz y potente que admite la búsqueda de texto completo en .NET. Facilita la búsqueda de texto y le proporciona un amplio conjunto de API para técnicas de búsqueda de texto rápidas y fáciles de usar.
Además, hay una cosa que Lucene no ofrece y es la escalabilidad. Las aplicaciones de Lucene suelen escribir datos en un archivo y almacenarlos en el disco, lo que genera una asignación de memoria significativa. NCache proporciona una Lucene distribuido característica que hace que sus aplicaciones Lucene sean escalables y distribuidas. También proporciona una alternativa linealmente escalable y distribuida al problema de un único punto de falla.
NCache Detalles Funcionamiento de Distributed Lucene Documentos de Lucene distribuidos
Para obtener más información sobre Distributed Lucene, está funcionando y por qué debería ser su opción preferida, eche un vistazo a esto Distributed Lucene: búsqueda de texto completo en .NET para escalabilidad. Antes de entrar en los detalles de Distributed Lucene, analicemos una solución de Distributed Lucene que demuestra el flujo de trabajo básico.
El ejemplo de código a continuación muestra un Lucene distribuido que realiza principalmente estos tres pasos:
- Inicializa el NCache Directorio.
- Indexar los documentos para realizar una búsqueda sobre ellos.
- Realizar una búsqueda en los documentos indexados.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
{ // Specify the cache name that is used for Lucene string cache = "LuceneCache"; // Specify the index name to create the indexes string indexName = "ProductIndex"; // Create a directory and open it on the cache and the index path Directory directory = NCacheDirectory.Open(cache, indexName); // Specify the analyzer used to analyze data Analyzer analyzer = new StandardAnalyzer(LuceneVersion.LUCENE_48); // Create an indexWriterConfig which holds all the configurations to create an instance of the writer IndexWriterConfig config = new IndexWriterConfig(LuceneVersion.LUCENE_48, analyzer); // Create the indexWriter with the analyzer and the configuration IndexWriter indexWriter = new IndexWriter(directory, config); // Add the products information that is to be indexed Product[] products = FetchProductsFromDB(); foreach (var prod in products) { // Create a document and add fields to it Document doc = new Document(); doc.Add(new TextField("id", prod.ProductID(), Field.Store.YES)); doc.Add(new TextField("name", prod.ProductName, Field.Store.NO)); doc.Add(new TextField("category", prod.Category, Field.Store.YES)); doc.Add(new TextField("description", prod.Description, Field.Store.YES)); // Writer is created previously indexWriter.AddDocument(doc); // Call ‘Commit’ to save the changes indexWriter.Commit(); } // Open a new reader instance IndexReader reader = indexWriter.GetReader(true); // A searcher is opened to perform searching IndexSearcher indexSearcher = new IndexSearcher(reader); // Specify the searchTerm and the fieldName string searchTerm = "Beverages"; string fieldName = "Category"; LuceneVersion version = LuceneVersion.LUCENE_48; // Create a query parser and parse the query with the parser // Analyzer is whitespace analyzer as specified beforehand QueryParser parser = new QueryParser(version, fieldName, analyzer); Query query = parser.Parse(searchTerm); // Returns the top 10 hits from the result set ScoreDoc[] docsFound = indexSearcher.Search(query, 10).ScoreDocs; // Closes all the files associated with this index reader.Dispose(); } catch(Exception ex) { // Handle Lucene exceptions } |
En este blog, nos centramos en los pasos detallados y el funcionamiento de Lucene distribuido para la búsqueda de texto completo.
NCache Detalles Funcionamiento de Distributed Lucene Componentes y descripción general de Lucene
¿Cómo migrar a Distributed Lucene?
Lucene distribuido funciona igual que Lucene. Una de las principales ventajas de usar Lucene distribuido es que le brinda la misma API que Lucene. Como usuario de Lucene, obtiene la escalabilidad que desea con un complemento de cambio de código de una sola línea. solo tienes que usar NCache Directory y su aplicación está lista para funcionar. Hay muy pocos cambios de comportamiento y API en Lucene distribuido que se enumeran en la documentación aquí.
Echemos un vistazo más de cerca a estos pasos desde un aspecto técnico.
Paso 1: Conexión a NCache Directorio
Empecemos por presentar NCache en su aplicación .NET usando Lucene. El paso principal es reemplazar el paquete Lucene.NET Nuget de su biblioteca con NCacheEl paquete Nuget de . NCache El directorio, como sugiere el nombre, es una clase base para almacenar los índices para hacer que los índices sean escalables. Lucene.NET tiene múltiples implementaciones de directorios para este propósito, pero la más utilizada es FSDirectory. Entonces, el primer paso es establecer una conexión con el NCache Directorio.
A continuación se muestra el código que lo conecta a un caché llamado “lucenecache” y abre el directorio proporcionado en todos los servidores existentes siempre que este directorio ya exista. De lo contrario, simplemente crea un nuevo directorio con el nombre proporcionado.
1 |
var indexDirectory = NCacheDirectory.Open("luceneCache", new DirectoryInfo("lucene-index-path")); |
Con este, NCache requiere otro pequeño paso para usar Distributed Lucene. Usando cualquier herramienta de administración, habilite el índice de Lucene para el caché usando Distributed Lucene. Por favor refiérase a así capítulo en NCache Documentación de pautas para hacerlo.
Configurar Lucene Lucene distribuido para la búsqueda empresarial Documentos de Lucene distribuidos
Paso 2: crear índices de Lucene distribuidos con NCache
Ahora que NCache se incorpora a su aplicación Lucene, viene la fase de escritura de datos. Como se discutió anteriormente, Lucene indexa sus registros en forma de índices. Estos índices se mantienen en los nodos por separado proporcionando escalabilidad lineal. La distribución de documentos entre los nodos de caché es manejada automáticamente por NCache.
Los documentos se forman a partir de campos que son pares clave-valor. Cada campo contiene el texto que usted desea que pueda buscar. Las otras partes del constructor del campo contienen instrucciones para manejar un campo individual.
Estos documentos se almacenan en el NCache Directorio en forma de índices invertidos de Lucene. Lucene desglosa el texto en forma de fichas. Este proceso de desglose de textos para la indexación se realiza mediante el uso de analizadores. Hay varios tipos de analizadores como analizadores de espacios en blanco or analizadores estándar. Esta tokenización de datos ayuda a una búsqueda de datos más rápida, ya que el objetivo principal de los analizadores es eliminar las palabras irrelevantes e indexar el resto de los datos en los que se realiza la búsqueda. Para obtener un conocimiento completo de los analizadores, consulte esta página.
Los documentos se indexan en el directorio mediante IndexWriter. IndexWriter es responsable de realizar todas las operaciones de escritura en el caché. Más precisamente, puede agregar otras propiedades de campo para que la búsqueda sea eficiente, como FieldStore. El siguiente código explica minuciosamente la escritura de documentos (en masa) en el caché y, como resultado, la creación de índices en todos los servidores de caché. Asegúrese de llamar a Commit después de cada operación de escritura; de lo contrario, la operación no se registra para realizar la búsqueda.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
public int AddDocuments () { var analyzer = new StandardAnalyzer(LuceneVersion.LUCENE_48); var writerConfig = new IndexWriterConfig (LuceneVersion.LUCENE_48, analyzer); var indexWriter = new IndexWriter (indexDirectory, writerConfig); var docCount = 0; // Fetching repository info from data source using (var enumerator = dataProvider.GetProductFTSEnumerator ()) { while (enumerator.MoveNext ()) { docs.Add (enumerator.Current.GetLuceneDocument ()); docCount++; // Perform commit after the chunk of code if (docs.Count == BULK_SIZE) { indexWriter.AddDocuments (docs); //Flush and make it ready for search indexWriter.Commit (); docs.Clear (); //Remove the added documents } } } // Return the count of added documents return docCount; } |
NCache Detalles Funcionamiento de Distributed Lucene Índices geoespaciales para Lucene distribuido
Paso 3: búsqueda de texto completo en los datos con escalabilidad
La tarea real de buscar datos en el caché usando Lucene distribuido viene en este paso. Similar a la indexación de datos, las lecturas también se realizan en todos los nodos de la memoria caché y los resultados de la búsqueda se fusionan eventualmente. Esto también aumenta la escalabilidad de lectura y hace que la búsqueda sea más rápida.
Similar a IndexWriter en Lucene, hay un Buscador de índices que hace todo el trabajo pesado para realizar las operaciones de lectura de datos basadas en la búsqueda. IndexSearcher pasa un analizador, y se recomienda encarecidamente utilizar el mismo analizador para la búsqueda, que se utilizó anteriormente para escribir los datos; de lo contrario, los resultados son inconsistentes.
Lo siguiente que usa Lucene para realizar búsquedas es el consultas. Hay una amplia gama de clases de consulta integradas en Lucene según sus necesidades junto con una sintaxis específica de Lucene. Estas consultas hacen que su búsqueda sea bastante eficiente, por ejemplo, hay una consulta con comodines que realiza una búsqueda con comodines y presenta los resultados de la búsqueda en consecuencia. Algunos otros tipos de consulta son TermQuery, BooleanQuery y SpanQuery.
Los resultados de la búsqueda se devuelven en forma de aciertos, que es una lista de documentos devueltos como resultado de la búsqueda realizada. Estos hits se pueden repetir para obtener el documento real que coincida con la consulta.
El código proporcionado a continuación lo ayudará a presenciar la búsqueda realizada en los índices de Lucene. IndexSearcher usa IndexReader para obtener los resultados. Se utiliza una consulta para realizar la búsqueda real en los datos indexados. Un QueryParser analiza la consulta textual proporcionada por el usuario de acuerdo con el analizador y los términos de búsqueda y los resultados se devuelven en forma de TopDocs.
En el ejemplo que se muestra a continuación, se aplica un QueryWrapperFilter en la categoría de Productos y los resultados de la búsqueda se ordenan por relevancia. La consulta aplica borrosidad a todos los términos para proporcionar resultados óptimos.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
public Tuple<long, List<RepositoryInfo>> Search (string searchTerm, int top = 100, string category = null) { long totalHints = 0; var repoList = new List<ProductFTS> (); // Now create the IndexSearcher instance to search the data // directoryReader is the IndexReader instance which uses the IndexWriter var searcher = new IndexSearcher (directoryReader); try { TopDocs topDocs = null; var queryParser = new MultiFieldQueryParser (Version, Fields, analyzer); var query = new BooleanQuery (); // Split the search term into multiple search words to make fuzzy query string[] terms = searchTerm.Split (new [] { " " }, StringSplitOptions.RemoveEmptyEntries); foreach (string term in terms) query.Add (queryParser.Parse (term.Replace ("~", "") + "~"), Occur.MUST); // remove the duplicate ~, if already exits if (!string.IsNullOrEmpty (category)) { var filter = new QueryWrapperFilter (new TermQuery (new Term (CATEGORY_FIELD, category))); // Performs the search based on the filter applied topDocs = searcher.Search (query, filter, top, Sort.RELEVANCE); } else { topDocs = searcher.Search (query, top, sort : Sort.RELEVANCE); } totalHits = topDocs.TotalHits; repoList = GetSearchedDocs (searcher, topDocs); } return new Tuple<long, List<ProductFTS>> (totalHits, repoList); } |
A continuación, puede implementar su lógica empresarial para iterar los resultados de búsqueda a partir de las visitas.
Conclusión
Lucene es un motor de búsqueda altamente eficiente para realizar búsquedas de texto completo en sus datos, pero carece de escalabilidad. NCache se puede usar con Lucene para hacerlo escalable con muy poco esfuerzo. El Lucene distribuido escalable hace que su aplicación no solo sea más rápida, sino que también lo ayuda a lidiar con el gran contratiempo del punto único de falla. NCache se puede conectar fácilmente a su aplicación .NET con un cambio de código de una sola línea, así que considérelo como la mejor opción posible para su aplicación Lucene escalable.