views:

365

answers:

3

Has anyone managed to get nhibernate.search (Lucene) to work with S#arp Architecture? I think I have it all wired up correctly except Luke shows no records or indexes when I run my indexing method. The index files for the entity are created (segments.gen & segments_1) but both are 1kb in size which explains why Luke shows no data.

I execute no other code specific to getting search to work, am I missing some initialisation calls? I assume the listeners get picked up automatically by nhibernate.

In my Web project I have:

NHibernate.config

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
  <session-factory>
    <property name="connection.connection_string">Data Source=.\SQLEXPRESS;Database=MyDatabase;Integrated Security=True;</property>
    <property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
    <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
    <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
    <property name="show_sql">true</property>
    <property name="generate_statistics">true</property>
    <property name="connection.release_mode">auto</property>
    <property name="adonet.batch_size">500</property>
    <property name="proxyfactory.factory_class">NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle</property>

    <listener class='NHibernate.Search.Event.FullTextIndexEventListener, NHibernate.Search' type='post-insert'/>
    <listener class='NHibernate.Search.Event.FullTextIndexEventListener, NHibernate.Search' type='post-update'/>
    <listener class='NHibernate.Search.Event.FullTextIndexEventListener, NHibernate.Search' type='post-delete'/>
  </session-factory>
</hibernate-configuration>

Web.Config

<configSections>
  ...
  <section name="nhs-configuration" type="NHibernate.Search.Cfg.ConfigurationSectionHandler, NHibernate.Search" requirePermission="false" />
</configSections>

<nhs-configuration xmlns='urn:nhs-configuration-1.0'>
  <search-factory>
    <property name="hibernate.search.default.directory_provider">NHibernate.Search.Store.FSDirectoryProvider, NHibernate.Search</property>
    <property name="hibernate.search.default.indexBase">~\Lucene</property>
  </search-factory>
</nhs-configuration>

My entity is decorated as follows:

[Indexed(Index = "Posting")] 
public class Posting : Entity
{
    [DocumentId]
    public new virtual int Id
    {
        get { return base.Id; }
        protected set { base.Id = value; }
    }

    [Field(Index.Tokenized, Store = Store.Yes)]
    [Analyzer(typeof(StandardAnalyzer))]
    public virtual string Title { get; set; }

    [Field(Index.Tokenized, Store = Store.Yes)]
    [Analyzer(typeof(StandardAnalyzer))]
    public virtual string Description { get; set; }

    public virtual DateTime CreatedDate { get; set; }
    ...
}

And I run the following to create the index

public void BuildSearchIndex()
{
    FSDirectory directory = null;
    IndexWriter writer = null;

    var type = typeof(Posting);

    var info = new DirectoryInfo(GetIndexDirectory());

    if (info.Exists)
    {
        info.Delete(true);
    }

    try
    {
        directory = FSDirectory.GetDirectory(Path.Combine(info.FullName, type.Name), true);
        writer = new IndexWriter(directory, new StandardAnalyzer(), true);
    }
    finally
    {
        if (directory != null)
        {
            directory.Close();
        }

        if (writer != null)
        {
            writer.Close();
        }
    }

    var fullTextSession = Search.CreateFullTextSession(this.Session);

    // select all Posting objects from NHibernate and add them to the Lucene index
    foreach (var instance in Session.CreateCriteria(typeof(Posting)).List<Posting>())
    {
        fullTextSession.Index(instance);
    }
}

private static string GetIndexDirectory()
{
    var nhsConfigCollection = CfgHelper.LoadConfiguration();
    var property = nhsConfigCollection.DefaultConfiguration.Properties["hibernate.search.default.indexBase"];
    var fi = new FileInfo(property);
    return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fi.Name);
}
A: 

Jordan, are you using the latest bits from NHContrib for NHibernate.Search? I just recently updated my bits and I am running into the same situation you are. It works for me on older bits, from about July. But I can't get my indexes to create either. Your config looks right, same as mine. And your indexing method looks good too.

Ryan Kelley
Yeah this is from the latest Contrib source. Only just started on this the days before xmas so haven't worked with any older source.
Jordan
I am working on this issue as well, will post any news if I find a solution then.
Ryan Kelley
I got mine to work, for me it was an issue with 1 of my fields that I had indexed throwing an exception when NH Search/lucene tried to access it.
Ryan Kelley
How did you track that down? I don't get any errors. I only have one entity indexed, and only two properties on that (as detailed above). Can you give some details as to the error and how you tracked it down?
Jordan
+1  A: 

Found an answer to my question so here it is in case anyone else comes by this problem.

NHS configuration in web.config contained such lines:

<property name="hibernate.search.default.directory_provider">NHibernate.Search.Store.FSDirectoryProvider, NHibernate.Search</property>
<property name="hibernate.search.default.indexBase">~\SearchIndex</property>

First line should be removed because in this case NHS consider it as though index shares. It is known NHibernateSearch issue.

If the site is run from IIS, Network Service should have all permissions on search index directory.

Jordan
A: 

Jordan, there is now an alternative to attribute based Lucene.NET mapping called FluentNHibernate.Search, this project is hosted on codeplex.

http://fnhsearch.codeplex.com/

public class BookSearchMap : DocumentMap<Book>
{
    public BookSearchMap()
    {
        Id(p => p.BookId).Field("BookId").Bridge().Guid();
        Name("Book");
        Boost(500);
        Analyzer<StandardAnalyzer>();

        Map(x => x.Title)
            .Analyzer<StandardAnalyzer>()
            .Boost(500);

        Map(x => x.Description)
            .Boost(500)
            .Name("Description")
            .Store().Yes()
            .Index().Tokenized();
    }
}
Yoann. B