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