Thom
Thom

Reputation: 2503

Polymorphic queries with NHibernate Search

I have multiple entities stored in a single NHibernate Search index, in the hope that I'd be able to query over all of them at once. The use case is a simple search page which returns mixed results. So, for example, the code could look like this:

public interface ISearchable {}

[Indexed(Index = "TheIndex")]
public class SearchableEntityA : ISearchable
{
    // Some [Field]s
}

[Indexed(Index = "TheIndex")]
public class SearchableEntityB : ISearchable
{
    // Some other [Field]s
}

This all indexes fine, and of course is queryable in raw NHibernate like so:

session.CreateCriteria<ISearchable>().List<ISearchable>();

I have some fields on ISearchable, but these aren't specifically referenced in NHibernate mappings.

My hope was that I could just say:

var query = "some keyword";
fullTextSession.CreateFullTextQuery<ISearchable>(query).List<ISearchable>();

And retrieve a list of ISearchables, containing results from various different entities. However, the reality is that it throws NHibernate.HibernateException: Not a mapped entity: NetComposites.Model.ISearchable.

So, what's the simplest way to achieve something resembling polymorphic queries with NHibernate Search?

Upvotes: 2

Views: 516

Answers (1)

Thom
Thom

Reputation: 2503

An overload of CreateFullTextQuery exists that allows you to specify the types to search:

fullTextSession.CreateFullTextQuery(query, typeof(EntityA), typeof(EntityB)).List<ISearchable>();

It's a little clunky having to specify all the types, but they load fine. The only remaining problem I have is that my assumption that you could just do an all fields search by default was incorrect, so it requires building a MultiFieldQueryParser over all properties of all searchable entities:

private static Query ParseQuery(string query, IFullTextSession searchSession)
{
    var parser = new MultiFieldQueryParser(GetAllFieldNames(searchSession), new StandardAnalyzer());
    return parser.Parse(query);
}

private static string[] GetAllFieldNames(IFullTextSession searchSession)
{
    var reader =
        searchSession.SearchFactory.ReaderProvider.OpenReader(
            searchSession.SearchFactory.GetDirectoryProviders(typeof (Company)));
    var fieldNames = reader.GetFieldNames(IndexReader.FieldOption.ALL);
    return fieldNames.Cast<string>().ToArray();
}

Upvotes: 2

Related Questions