2010-06-02 15:56:54 -07:00
|
|
|
|
using System;
|
2010-06-03 13:12:07 -07:00
|
|
|
|
using System.Collections.Generic;
|
2010-06-02 15:56:54 -07:00
|
|
|
|
using System.IO;
|
2010-06-03 13:12:07 -07:00
|
|
|
|
using System.Linq;
|
2010-07-09 13:16:02 -07:00
|
|
|
|
using Lucene.Models;
|
2010-06-02 15:56:54 -07:00
|
|
|
|
using Lucene.Net.Analysis;
|
|
|
|
|
using Lucene.Net.Analysis.Standard;
|
|
|
|
|
using Lucene.Net.Documents;
|
|
|
|
|
using Lucene.Net.Index;
|
2010-06-29 12:24:09 -07:00
|
|
|
|
using Lucene.Net.Search;
|
2010-06-02 15:56:54 -07:00
|
|
|
|
using Lucene.Net.Store;
|
2010-07-09 13:16:02 -07:00
|
|
|
|
using System.Xml.Linq;
|
2010-06-02 15:56:54 -07:00
|
|
|
|
using Orchard.Environment.Configuration;
|
|
|
|
|
using Orchard.FileSystems.AppData;
|
2010-07-09 13:16:02 -07:00
|
|
|
|
using Orchard.Indexing;
|
2010-06-22 10:21:24 -07:00
|
|
|
|
using Orchard.Localization;
|
2010-06-02 15:56:54 -07:00
|
|
|
|
using Orchard.Logging;
|
2010-06-17 16:21:29 -07:00
|
|
|
|
using Directory = Lucene.Net.Store.Directory;
|
|
|
|
|
using Version = Lucene.Net.Util.Version;
|
2010-06-02 15:56:54 -07:00
|
|
|
|
|
2010-07-09 13:16:02 -07:00
|
|
|
|
namespace Lucene.Services {
|
2010-06-02 15:56:54 -07:00
|
|
|
|
/// <summary>
|
2010-06-03 13:12:07 -07:00
|
|
|
|
/// Represents the default implementation of an IIndexProvider, based on Lucene
|
2010-06-02 15:56:54 -07:00
|
|
|
|
/// </summary>
|
2010-06-17 16:21:29 -07:00
|
|
|
|
public class LuceneIndexProvider : IIndexProvider {
|
2010-06-02 15:56:54 -07:00
|
|
|
|
private readonly IAppDataFolder _appDataFolder;
|
|
|
|
|
private readonly ShellSettings _shellSettings;
|
|
|
|
|
public static readonly Version LuceneVersion = Version.LUCENE_29;
|
2010-06-07 12:26:32 -07:00
|
|
|
|
private readonly Analyzer _analyzer ;
|
2010-06-02 15:56:54 -07:00
|
|
|
|
private readonly string _basePath;
|
2010-06-04 16:29:50 -07:00
|
|
|
|
public static readonly DateTime DefaultMinDateTime = new DateTime(1980, 1, 1);
|
|
|
|
|
public static readonly string Settings = "Settings";
|
|
|
|
|
public static readonly string LastIndexUtc = "LastIndexedUtc";
|
2010-06-02 15:56:54 -07:00
|
|
|
|
|
2010-06-17 16:21:29 -07:00
|
|
|
|
public LuceneIndexProvider(IAppDataFolder appDataFolder, ShellSettings shellSettings) {
|
2010-06-02 15:56:54 -07:00
|
|
|
|
_appDataFolder = appDataFolder;
|
|
|
|
|
_shellSettings = shellSettings;
|
2010-06-07 12:26:32 -07:00
|
|
|
|
_analyzer = CreateAnalyzer();
|
2010-06-02 15:56:54 -07:00
|
|
|
|
|
|
|
|
|
// TODO: (sebros) Find a common way to get where tenant's specific files should go. "Sites/Tenant" is hard coded in multiple places
|
2010-06-12 12:42:04 -07:00
|
|
|
|
_basePath = _appDataFolder.Combine("Sites", _shellSettings.Name, "Indexes");
|
2010-06-02 15:56:54 -07:00
|
|
|
|
|
|
|
|
|
Logger = NullLogger.Instance;
|
|
|
|
|
|
|
|
|
|
// Ensures the directory exists
|
2010-06-04 16:29:50 -07:00
|
|
|
|
EnsureDirectoryExists();
|
2010-06-22 10:21:24 -07:00
|
|
|
|
|
|
|
|
|
T = NullLocalizer.Instance;
|
|
|
|
|
Logger = NullLogger.Instance;
|
2010-06-04 16:29:50 -07:00
|
|
|
|
}
|
|
|
|
|
|
2010-06-22 10:21:24 -07:00
|
|
|
|
public Localizer T { get; set; }
|
|
|
|
|
public ILogger Logger { get; set; }
|
|
|
|
|
|
2010-06-07 12:26:32 -07:00
|
|
|
|
public static Analyzer CreateAnalyzer() {
|
|
|
|
|
// StandardAnalyzer does lower-case and stop-word filtering. It also removes punctuation
|
|
|
|
|
return new StandardAnalyzer(LuceneVersion);
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-04 16:29:50 -07:00
|
|
|
|
private void EnsureDirectoryExists() {
|
2010-06-02 15:56:54 -07:00
|
|
|
|
var directory = new DirectoryInfo(_appDataFolder.MapPath(_basePath));
|
|
|
|
|
if(!directory.Exists) {
|
|
|
|
|
directory.Create();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected virtual Directory GetDirectory(string indexName) {
|
2010-06-12 12:42:04 -07:00
|
|
|
|
var directoryInfo = new DirectoryInfo(_appDataFolder.MapPath(_appDataFolder.Combine(_basePath, indexName)));
|
2010-06-02 15:56:54 -07:00
|
|
|
|
return FSDirectory.Open(directoryInfo);
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-17 16:21:29 -07:00
|
|
|
|
private static Document CreateDocument(LuceneDocumentIndex indexDocument) {
|
2010-06-02 15:56:54 -07:00
|
|
|
|
var doc = new Document();
|
|
|
|
|
|
|
|
|
|
indexDocument.PrepareForIndexing();
|
|
|
|
|
foreach(var field in indexDocument.Fields) {
|
|
|
|
|
doc.Add(field);
|
|
|
|
|
}
|
|
|
|
|
return doc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool Exists(string indexName) {
|
2010-06-12 12:42:04 -07:00
|
|
|
|
return new DirectoryInfo(_appDataFolder.MapPath(_appDataFolder.Combine(_basePath, indexName))).Exists;
|
2010-06-02 15:56:54 -07:00
|
|
|
|
}
|
|
|
|
|
|
2010-06-04 17:42:20 -07:00
|
|
|
|
public bool IsEmpty(string indexName) {
|
2010-06-04 18:41:02 -07:00
|
|
|
|
if ( !Exists(indexName) ) {
|
2010-06-04 17:42:20 -07:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var reader = IndexReader.Open(GetDirectory(indexName), true);
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
return reader.NumDocs() == 0;
|
|
|
|
|
}
|
|
|
|
|
finally {
|
|
|
|
|
reader.Close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-04 18:41:02 -07:00
|
|
|
|
public int NumDocs(string indexName) {
|
|
|
|
|
if ( !Exists(indexName) ) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var reader = IndexReader.Open(GetDirectory(indexName), true);
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
return reader.NumDocs();
|
|
|
|
|
}
|
|
|
|
|
finally {
|
|
|
|
|
reader.Close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-02 15:56:54 -07:00
|
|
|
|
public void CreateIndex(string indexName) {
|
2010-07-29 17:44:37 -07:00
|
|
|
|
var writer = new IndexWriter(GetDirectory(indexName), _analyzer, true, IndexWriter.MaxFieldLength.UNLIMITED);
|
|
|
|
|
writer.Close();
|
2010-06-02 15:56:54 -07:00
|
|
|
|
|
|
|
|
|
Logger.Information("Index [{0}] created", indexName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void DeleteIndex(string indexName) {
|
2010-07-29 17:44:37 -07:00
|
|
|
|
new DirectoryInfo(_appDataFolder.MapPath(_appDataFolder.Combine(_basePath, indexName)))
|
|
|
|
|
.Delete(true);
|
2010-06-04 16:29:50 -07:00
|
|
|
|
|
2010-07-29 17:44:37 -07:00
|
|
|
|
var settingsFileName = GetSettingsFileName(indexName);
|
|
|
|
|
if (File.Exists(settingsFileName)) {
|
|
|
|
|
File.Delete(settingsFileName);
|
2010-06-04 16:29:50 -07:00
|
|
|
|
}
|
2010-06-02 15:56:54 -07:00
|
|
|
|
}
|
|
|
|
|
|
2010-06-17 16:21:29 -07:00
|
|
|
|
public void Store(string indexName, IDocumentIndex indexDocument) {
|
|
|
|
|
Store(indexName, new [] { (LuceneDocumentIndex)indexDocument });
|
2010-06-02 15:56:54 -07:00
|
|
|
|
}
|
|
|
|
|
|
2010-06-17 16:21:29 -07:00
|
|
|
|
public void Store(string indexName, IEnumerable<IDocumentIndex> indexDocuments) {
|
|
|
|
|
Store(indexName, indexDocuments.Cast<LuceneDocumentIndex>());
|
2010-06-03 13:12:07 -07:00
|
|
|
|
}
|
|
|
|
|
|
2010-06-17 16:21:29 -07:00
|
|
|
|
public void Store(string indexName, IEnumerable<LuceneDocumentIndex> indexDocuments) {
|
2010-07-29 17:44:37 -07:00
|
|
|
|
if (indexDocuments.AsQueryable().Count() == 0) {
|
2010-06-03 13:12:07 -07:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-29 12:24:09 -07:00
|
|
|
|
// Remove any previous document for these content items
|
|
|
|
|
Delete(indexName, indexDocuments.Select(i => i.ContentItemId));
|
|
|
|
|
|
2010-07-29 17:44:37 -07:00
|
|
|
|
var writer = new IndexWriter(GetDirectory(indexName), _analyzer, false, IndexWriter.MaxFieldLength.UNLIMITED);
|
|
|
|
|
LuceneDocumentIndex current = null;
|
2010-06-02 15:56:54 -07:00
|
|
|
|
|
2010-07-29 17:44:37 -07:00
|
|
|
|
try {
|
2010-07-29 15:44:15 -07:00
|
|
|
|
|
2010-07-29 17:44:37 -07:00
|
|
|
|
foreach (var indexDocument in indexDocuments) {
|
|
|
|
|
current = indexDocument;
|
|
|
|
|
var doc = CreateDocument(indexDocument);
|
2010-06-29 12:24:09 -07:00
|
|
|
|
|
2010-07-29 17:44:37 -07:00
|
|
|
|
writer.AddDocument(doc);
|
|
|
|
|
Logger.Debug("Document [{0}] indexed", indexDocument.ContentItemId);
|
2010-06-03 13:12:07 -07:00
|
|
|
|
}
|
2010-06-02 15:56:54 -07:00
|
|
|
|
}
|
2010-07-29 17:44:37 -07:00
|
|
|
|
catch (Exception ex) {
|
|
|
|
|
Logger.Error(ex, "An unexpected error occured while add the document [{0}] from the index [{1}].", current.ContentItemId, indexName);
|
|
|
|
|
}
|
|
|
|
|
finally {
|
|
|
|
|
writer.Optimize();
|
|
|
|
|
writer.Close();
|
|
|
|
|
}
|
2010-06-02 15:56:54 -07:00
|
|
|
|
}
|
|
|
|
|
|
2010-06-03 13:12:07 -07:00
|
|
|
|
public void Delete(string indexName, int documentId) {
|
|
|
|
|
Delete(indexName, new[] { documentId });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Delete(string indexName, IEnumerable<int> documentIds) {
|
2010-06-29 12:24:09 -07:00
|
|
|
|
if (!documentIds.Any()) {
|
2010-06-03 13:12:07 -07:00
|
|
|
|
return;
|
|
|
|
|
}
|
2010-06-29 12:24:09 -07:00
|
|
|
|
|
2010-07-29 17:44:37 -07:00
|
|
|
|
var writer = new IndexWriter(GetDirectory(indexName), _analyzer, false, IndexWriter.MaxFieldLength.UNLIMITED);
|
2010-06-02 15:56:54 -07:00
|
|
|
|
|
2010-07-29 17:44:37 -07:00
|
|
|
|
try {
|
|
|
|
|
var query = new BooleanQuery();
|
2010-06-29 12:24:09 -07:00
|
|
|
|
|
|
|
|
|
try {
|
2010-07-29 17:44:37 -07:00
|
|
|
|
foreach (var id in documentIds) {
|
|
|
|
|
query.Add(new BooleanClause(new TermQuery(new Term("id", id.ToString())), BooleanClause.Occur.SHOULD));
|
2010-07-29 15:44:15 -07:00
|
|
|
|
}
|
2010-07-29 17:44:37 -07:00
|
|
|
|
|
|
|
|
|
writer.DeleteDocuments(query);
|
2010-06-29 12:24:09 -07:00
|
|
|
|
}
|
2010-07-29 17:44:37 -07:00
|
|
|
|
catch (Exception ex) {
|
|
|
|
|
Logger.Error(ex, "An unexpected error occured while removing the documents [{0}] from the index [{1}].", String.Join(", ", documentIds), indexName);
|
2010-06-02 15:56:54 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
2010-07-29 17:44:37 -07:00
|
|
|
|
finally {
|
|
|
|
|
writer.Close();
|
|
|
|
|
}
|
2010-06-02 15:56:54 -07:00
|
|
|
|
}
|
|
|
|
|
|
2010-06-17 16:21:29 -07:00
|
|
|
|
public IDocumentIndex New(int documentId) {
|
2010-06-22 10:21:24 -07:00
|
|
|
|
return new LuceneDocumentIndex(documentId, T);
|
2010-06-02 15:56:54 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ISearchBuilder CreateSearchBuilder(string indexName) {
|
2011-01-11 16:38:27 -08:00
|
|
|
|
return new LuceneSearchBuilder(GetDirectory(indexName)) { Logger = Logger };
|
2010-06-02 15:56:54 -07:00
|
|
|
|
}
|
|
|
|
|
|
2010-06-04 16:29:50 -07:00
|
|
|
|
private string GetSettingsFileName(string indexName) {
|
2010-06-12 12:42:04 -07:00
|
|
|
|
return _appDataFolder.MapPath(_appDataFolder.Combine(_basePath, indexName + ".settings.xml"));
|
2010-06-04 16:29:50 -07:00
|
|
|
|
}
|
|
|
|
|
|
2010-07-11 12:11:38 -07:00
|
|
|
|
public DateTime? GetLastIndexUtc(string indexName) {
|
2010-06-04 16:29:50 -07:00
|
|
|
|
var settingsFileName = GetSettingsFileName(indexName);
|
|
|
|
|
|
2010-07-11 12:11:38 -07:00
|
|
|
|
if (!File.Exists(settingsFileName))
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
return DateTime.Parse(XDocument.Load(settingsFileName).Descendants(LastIndexUtc).First().Value);
|
2010-06-04 16:29:50 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void SetLastIndexUtc(string indexName, DateTime lastIndexUtc) {
|
|
|
|
|
if ( lastIndexUtc < DefaultMinDateTime ) {
|
|
|
|
|
lastIndexUtc = DefaultMinDateTime;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
XDocument doc;
|
|
|
|
|
var settingsFileName = GetSettingsFileName(indexName);
|
|
|
|
|
if ( !File.Exists(settingsFileName) ) {
|
|
|
|
|
EnsureDirectoryExists();
|
|
|
|
|
doc = new XDocument(
|
|
|
|
|
new XElement(Settings,
|
|
|
|
|
new XElement(LastIndexUtc, lastIndexUtc.ToString("s"))));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
doc = XDocument.Load(settingsFileName);
|
|
|
|
|
doc.Element(Settings).Element(LastIndexUtc).Value = lastIndexUtc.ToString("s");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
doc.Save(settingsFileName);
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-11 12:11:38 -07:00
|
|
|
|
public IEnumerable<string> GetFields(string indexName) {
|
2010-06-18 12:22:06 -07:00
|
|
|
|
if ( !Exists(indexName) ) {
|
2010-07-11 12:11:38 -07:00
|
|
|
|
return Enumerable.Empty<string>();
|
2010-06-18 12:22:06 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var reader = IndexReader.Open(GetDirectory(indexName), true);
|
|
|
|
|
|
|
|
|
|
try {
|
2010-07-11 12:11:38 -07:00
|
|
|
|
return reader.GetFieldNames(IndexReader.FieldOption.ALL).ToList();
|
2010-06-18 12:22:06 -07:00
|
|
|
|
}
|
|
|
|
|
finally {
|
|
|
|
|
reader.Close();
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-06-02 15:56:54 -07:00
|
|
|
|
}
|
|
|
|
|
}
|