using System; using System.Collections.Generic; using System.Data.Common; using System.Linq; using System.Text; using ScrewTurn.Wiki.SearchEngine; namespace ScrewTurn.Wiki.Plugins.SqlCommon { /// /// Implements a SQL-based search engine index. /// public class SqlIndex : IIndex { private IIndexConnector connector; /// /// The stop words to be used while indexing new content. /// protected string[] stopWords = null; /// /// Initializes a new instance of the class. /// /// The connection object. public SqlIndex(IIndexConnector connector) { if(connector == null) throw new ArgumentNullException("connector"); this.connector = connector; this.stopWords = new string[0]; } /// /// Gets or sets the stop words to be used while indexing new content. /// /// public string[] StopWords { get { lock(this) { return stopWords; } } set { if(value == null) throw new ArgumentNullException("value", "Stop words cannot be null"); lock(this) { stopWords = value; } } } /// /// Gets the total count of unique words. /// /// Computing the result is O(1). public int TotalWords { get { return connector.GetCount(IndexElementType.Words); } } /// /// Gets the total count of documents. /// /// Computing the result is O(n*m), where n is the number of /// words in the index and m is the number of documents. public int TotalDocuments { get { return connector.GetCount(IndexElementType.Documents); } } /// /// Gets the total number of occurrences (count of words in each document). /// /// Computing the result is O(n), /// where n is the number of words in the index. public int TotalOccurrences { get { return connector.GetCount(IndexElementType.Occurrences); } } /// /// Completely clears the index (stop words are not affected). /// /// A state object that is passed to the IndexStorer SaveDate/DeleteData function. public void Clear(object state) { connector.ClearIndex(state); } /// /// Stores a document in the index. /// /// The document. /// The document keywords, if any, an empty array or null otherwise. /// The content of the document. /// A state object that is passed to the IndexStorer SaveDate/DeleteData function. /// The number of indexed words (including duplicates). /// Indexing the content of the document is O(n), /// where n is the total number of words in the document. public int StoreDocument(IDocument document, string[] keywords, string content, object state) { if(document == null) throw new ArgumentNullException("document"); if(keywords == null) keywords = new string[0]; if(content == null) throw new ArgumentNullException("content"); RemoveDocument(document, state); keywords = ScrewTurn.Wiki.SearchEngine.Tools.CleanupKeywords(keywords); // Prepare content words WordInfo[] contentWords = document.Tokenize(content); contentWords = ScrewTurn.Wiki.SearchEngine.Tools.RemoveStopWords(contentWords, stopWords); // Prepare title words WordInfo[] titleWords = document.Tokenize(document.Title); titleWords = ScrewTurn.Wiki.SearchEngine.Tools.RemoveStopWords(titleWords, stopWords); for(int i = 0; i < titleWords.Length; i++) { titleWords[i] = new WordInfo(titleWords[i].Text, titleWords[i].FirstCharIndex, titleWords[i].WordIndex, WordLocation.Title); } // Prepare keywords WordInfo[] words = new WordInfo[keywords.Length]; int count = 0; for(int i = 0; i < words.Length; i++) { words[i] = new WordInfo(keywords[i], (ushort)count, (ushort)i, WordLocation.Keywords); count += 1 + keywords[i].Length; } return connector.SaveDataForDocument(document, contentWords, titleWords, words, state); } /// /// Removes a document from the index. /// /// The document to remove. /// A state object that is passed to the IndexStorer SaveDate/DeleteData function. public void RemoveDocument(IDocument document, object state) { if(document == null) throw new ArgumentNullException("document"); connector.DeleteDataForDocument(document, state); } /// /// Performs a search in the index. /// /// The search parameters. /// The results. public SearchResultCollection Search(SearchParameters parameters) { if(parameters == null) throw new ArgumentNullException("parameters"); using(IWordFetcher fetcher = connector.GetWordFetcher()) { if(parameters.DocumentTypeTags == null) { return ScrewTurn.Wiki.SearchEngine.Tools.SearchInternal(parameters.Query, null, false, parameters.Options, fetcher); } else { return ScrewTurn.Wiki.SearchEngine.Tools.SearchInternal(parameters.Query, parameters.DocumentTypeTags, true, parameters.Options, fetcher); } } } } /// /// Implements a word fetcher for a SQL-based index. /// public class SqlWordFetcher : IWordFetcher { private DbConnection connection; private TryFindWord implementation; /// /// Initializes a new instance of the class. /// /// An open database connection. /// The method implementation. public SqlWordFetcher(DbConnection connection, TryFindWord implementation) { if(connection == null) throw new ArgumentNullException("connection"); if(implementation == null) throw new ArgumentNullException("implementation"); this.connection = connection; this.implementation = implementation; } /// /// Tries to get a word. /// /// The text of the word. /// The found word, if any, null otherwise. /// true if the word is found, false otherwise. public bool TryGetWord(string text, out Word word) { return implementation(text, out word, connection); } #region IDisposable Members /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { try { connection.Close(); } catch { } } #endregion } }