Lucene è un motore di ricerca efficiente e potente che supporta la ricerca full-text in .NET. Semplifica la ricerca di testo e ti fornisce un ricco set di API, per tecniche di ricerca di testo rapide e intuitive.
Inoltre, c'è una cosa che Lucene non offre, ed è la scalabilità. Le applicazioni Lucene di solito scrivono i dati su un file e li memorizzano sul disco, determinando una significativa allocazione di memoria. NCache fornisce un Lucene distribuita caratteristica che rende le tue applicazioni Lucene scalabili e distribuite. Fornisce inoltre un'alternativa linearmente scalabile e distribuita al problema di un singolo punto di errore.
NCache Dettagli Funzionamento di Lucene Distribuita Lucene Docs distribuito
Per ulteriori informazioni su Distributed Lucene, funziona e perché dovrebbe essere la tua opzione preferita dai un'occhiata a questo Lucene distribuito: ricerca full-text in .NET per la scalabilità. Prima di entrare nei dettagli di Distributed Lucene, esaminiamo una soluzione Distributed Lucene che dimostra il flusso di lavoro di base.
L'esempio di codice seguente mostra un Lucene distribuito che esegue principalmente questi tre passaggi:
- Inizializza il file NCache Elenco.
- Indicizzare i documenti per effettuare una ricerca su di essi.
- Eseguire una ricerca sui documenti indicizzati.
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 } |
In questo blog, ci concentriamo sui passaggi dettagliati e sul funzionamento di Lucene distribuito per la ricerca di testo completo.
NCache Dettagli Funzionamento di Lucene Distribuita Componenti e panoramica di Lucene
Come migrare a Lucene distribuita?
Distributed Lucene funziona esattamente come Lucene. Uno dei principali vantaggi dell'utilizzo di Lucene distribuito è che fornisce la stessa API di Lucene. Come utente Lucene, ottieni la scalabilità che desideri con un componente aggiuntivo di una singola modifica del codice di linea. Devi solo usare NCache Directory e la tua applicazione sono a posto. Ci sono pochissime modifiche comportamentali e API in Lucene distribuita elencate nella documentazione qui.
Diamo un'occhiata più da vicino a questi passaggi da un aspetto tecnico.
Passaggio 1: connessione a NCache elenco
Cominciamo con l'introduzione NCache nell'applicazione .NET utilizzando Lucene. Il passaggio principale consiste nel sostituire il pacchetto Lucene.NET Nuget dalla libreria con NCacheil pacchetto Nuget. NCache La directory, come suggerisce il nome, è una classe base per l'archiviazione degli indici per renderli scalabili. Lucene.NET ha più implementazioni di directory per questo scopo, ma la più comunemente usata è FSDirectory. Quindi, il primo passo è stabilire una connessione con il NCache Elenco.
Di seguito è riportato il codice che ti collega a una cache chiamata “luceneCache” e apre la directory fornita su tutti i server esistenti a condizione che questa directory esista già. In caso contrario, crea semplicemente una nuova directory con il nome fornito.
1 |
var indexDirectory = NCacheDirectory.Open("luceneCache", new DirectoryInfo("lucene-index-path")); |
Con questo, NCache richiede un altro piccolo passo per utilizzare Distributed Lucene. Utilizzando qualsiasi strumento di gestione, abilitare l'indice Lucene per la cache utilizzando Distributed Lucene. Per favore riferisci a questo capitolo in NCache Documentazione per le linee guida su come farlo.
Installa Lucene Lucene distribuito per la ricerca aziendale Lucene Docs distribuito
Passaggio 2: creazione di indici Lucene distribuiti con NCache
Ora che NCache è incorporato nella tua applicazione Lucene, arriva la fase di scrittura dei dati. Come discusso in precedenza, Lucene indicizza i tuoi record sotto forma di indici. Questi indici vengono mantenuti sui nodi separatamente fornendo scalabilità lineare. La distribuzione dei documenti tra i nodi della cache è gestita automaticamente da NCache.
I documenti sono formati da campi che sono coppie chiave-valore. Ogni campo contiene il testo che deve essere reso ricercabile dall'utente. Le altre parti del costruttore del campo contengono istruzioni per la gestione di un singolo campo.
Questi documenti sono archiviati nel NCache Directory sotto forma di indici invertiti Lucene. Lucene scompone il testo sotto forma di token. Questo processo di suddivisione dei testi per l'indicizzazione viene eseguito utilizzando gli analizzatori. Esistono diversi tipi di analizzatori come analizzatori di spazi bianchi or analizzatori standard. Questa tokenizzazione dei dati aiuta a velocizzare la ricerca dei dati poiché lo scopo principale degli analizzatori è rimuovere le parole non significative e indicizzare il resto dei dati su cui viene eseguita la ricerca. Per una conoscenza completa degli analizzatori fare riferimento a questa pagina.
I documenti vengono indicizzati nella directory utilizzando IndexWriter. IndexWriter è responsabile dell'esecuzione di tutte le operazioni di scrittura sulla cache. Più precisamente, puoi aggiungere altre proprietà del campo per rendere efficiente la ricerca come FieldStore. Il codice seguente spiega in dettaglio la scrittura di documenti (in blocco) nella cache e, di conseguenza, la creazione di indici su tutti i server della cache. Assicurati di chiamare Commit dopo ogni operazione di scrittura altrimenti l'operazione non viene registrata per eseguire la ricerca.
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 Dettagli Funzionamento di Lucene Distribuita Indici geospaziali per lucene distribuita
Passaggio 3: ricerca di testo completo nei dati con scalabilità
Il compito effettivo di ricerca dei dati nella cache utilizzando Lucene distribuito arriva in questo passaggio. Analogamente all'indicizzazione dei dati, le letture vengono eseguite anche su tutti i nodi della cache e i risultati della ricerca vengono eventualmente uniti. Ciò aumenta anche la scalabilità di lettura e rende la ricerca più veloce.
Simile a IndexWriter in Lucene, c'è un Cercatore di indici che fa tutto il lavoro pesante per eseguire le operazioni di lettura dei dati in base alla ricerca. IndexSearcher passa un analizzatore e si consiglia vivamente di utilizzare lo stesso analizzatore per la ricerca, utilizzato in precedenza per scrivere i dati, altrimenti i risultati non sono coerenti.
La prossima cosa che Lucene usa per eseguire ricerche è il file query. C'è una vasta gamma di classi di query integrate in Lucene secondo le tue esigenze insieme a una sintassi specifica di Lucene. Queste query rendono la tua ricerca abbastanza efficiente, ad esempio esiste una query con caratteri jolly che esegue una ricerca utilizzando caratteri jolly e visualizza i risultati della ricerca di conseguenza. Alcuni altri tipi di query sono TermQuery, BooleanQuery e SpanQuery.
I risultati della ricerca vengono restituiti sotto forma di risultati, che è un elenco di documenti restituiti a seguito della ricerca eseguita. Questi hit possono quindi essere ripetuti per ottenere il documento effettivo che corrisponde alla query.
Il codice fornito di seguito ti aiuterà a testimoniare la ricerca eseguita sugli indici Lucene. IndexSearcher utilizza IndexReader per recuperare i risultati. Una query viene utilizzata per eseguire la ricerca effettiva sui dati indicizzati. Un QueryParser analizza la query testuale fornita dall'utente in base all'analizzatore e ai termini di ricerca ei risultati vengono restituiti sotto forma di TopDocs.
Nell'esempio riportato di seguito, un QueryWrapperFilter viene applicato alla categoria Prodotti e i risultati della ricerca vengono ordinati per pertinenza. La query applica la sfocatura a tutti i termini per fornire risultati ottimali.
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); } |
Puoi quindi implementare la tua logica aziendale per iterare i risultati della ricerca dagli hit.
Conclusione
Lucene è un motore di ricerca altamente efficiente per eseguire ricerche di testo completo sui tuoi dati, ma manca di scalabilità. NCache può essere utilizzato con Lucene per renderlo scalabile con un minimo sforzo. Lucene distribuito scalabile rende la tua applicazione non solo più veloce, ma ti aiuta anche ad affrontare la grave battuta d'arresto di un singolo punto di errore. NCache può essere facilmente inserito nella tua applicazione .NET con una modifica del codice a riga singola, quindi considerala la migliore opzione possibile per la tua applicazione Lucene scalabile.