callumbwhyte / examine-facets

Powerful filtering and faceting directly within the Examine fluent API
MIT License
22 stars 6 forks source link

V9 support #12

Closed dawoe closed 3 months ago

dawoe commented 2 years ago

Hi Callum,

Will you be releasing a V9 version of this package ? Or is it not possible with the underlying dependencies like Bobo browse?

Dave

callumbwhyte commented 2 years ago

Hey @dawoe,

That is absolutely the plan, however Examine Facets will look a little different.

Lucene 4.8 has a faceting implementation out of the box, negating the need for 3rd party faceting systems like Bobo Browse (which isn't currently available anyway). My proposal is to keep the abstractions that exist currently in Examine Facets, ship a default implementation that uses Lucene (just like Examine does) and drop support for all 3rd party engines.

It's a project I've started but not made too much headway on yet - would happily accept any help, advice, or ideas!

Cheers, Callum

dawoe commented 2 years ago

I will get to you on helping out. Will probably need similar functionality too.

bjarnef commented 1 year ago

I was looking at this as well. A few things I noticed is that LuceneSearchResultsBase has been removed from Examine, so I have this instead.

public abstract class FacetSearchResults : LuceneSearchResults, IFacetResults
{
    public FacetSearchResults(ISearchContext searchContext)
        :base(Array.Empty<ISearchResult>(), 0)
    {
        Facets = new Dictionary<string, IFacetResult>();

        if (searchContext.GetSearcher() is not IndexSearcher indexSearcher)
        {
            throw new Exception("Searcher is invalid");
        }

        Searcher = indexSearcher;
    }

    ///<inheritdoc/>
    public IDictionary<string, IFacetResult> Facets { get; }

    /// <summary>
    /// Exposes the internal <see cref="IndexSearcher"/>
    /// </summary>
    public IndexSearcher Searcher { get; }
}

however when requesting results.GetFacets() in the following code, I got this:

image

if (!_examineManager.TryGetIndex(Umbraco.Cms.Core.Constants.UmbracoIndexes.ExternalIndexName, out IIndex index))
{
    throw new InvalidOperationException($"No index found by name {Umbraco.Cms.Core.Constants.UmbracoIndexes.ExternalIndexName}");
}

if (index is not LuceneIndex luceneIndex)
{
    throw new InvalidOperationException($"Index {Umbraco.Cms.Core.Constants.UmbracoIndexes.ExternalIndexName} is not a LuceneIndex");
}

var writer = luceneIndex.IndexWriter.IndexWriter;

var manager = new SearcherManager(writer, true, new SearcherFactory());

var multiSearcher = new MultiFacetSearcher(
    "FacetSearcher",
    manager,
    luceneIndex.DefaultAnalyzer,
    luceneIndex.FieldValueTypeCollection
);

var query = multiSearcher.CreateQuery()
    .NodeTypeAlias(Course.ModelTypeAlias);

query.And()
    .Facet("Duration")
    .MinHits(10)
    .MaxCount(100);

var results = query.Execute(new QueryOptions(0, 100));

var data = new
{
    Facets = results.GetFacets(),
    Results = results
};

Furthermore signature of Execute method has changed to:

ISearchResults Execute(QueryOptions options = null)
JohanReitsma83 commented 10 months ago

I was looking at this as well. A few things I noticed is that LuceneSearchResultsBase has been removed from Examine, so I have this instead.

public abstract class FacetSearchResults : LuceneSearchResults, IFacetResults
{
    public FacetSearchResults(ISearchContext searchContext)
        :base(Array.Empty<ISearchResult>(), 0)
    {
        Facets = new Dictionary<string, IFacetResult>();

        if (searchContext.GetSearcher() is not IndexSearcher indexSearcher)
        {
            throw new Exception("Searcher is invalid");
        }

        Searcher = indexSearcher;
    }

    ///<inheritdoc/>
    public IDictionary<string, IFacetResult> Facets { get; }

    /// <summary>
    /// Exposes the internal <see cref="IndexSearcher"/>
    /// </summary>
    public IndexSearcher Searcher { get; }
}

however when requesting results.GetFacets() in the following code, I got this:

image

if (!_examineManager.TryGetIndex(Umbraco.Cms.Core.Constants.UmbracoIndexes.ExternalIndexName, out IIndex index))
{
    throw new InvalidOperationException($"No index found by name {Umbraco.Cms.Core.Constants.UmbracoIndexes.ExternalIndexName}");
}

if (index is not LuceneIndex luceneIndex)
{
    throw new InvalidOperationException($"Index {Umbraco.Cms.Core.Constants.UmbracoIndexes.ExternalIndexName} is not a LuceneIndex");
}

var writer = luceneIndex.IndexWriter.IndexWriter;

var manager = new SearcherManager(writer, true, new SearcherFactory());

var multiSearcher = new MultiFacetSearcher(
    "FacetSearcher",
    manager,
    luceneIndex.DefaultAnalyzer,
    luceneIndex.FieldValueTypeCollection
);

var query = multiSearcher.CreateQuery()
    .NodeTypeAlias(Course.ModelTypeAlias);

query.And()
    .Facet("Duration")
    .MinHits(10)
    .MaxCount(100);

var results = query.Execute(new QueryOptions(0, 100));

var data = new
{
    Facets = results.GetFacets(),
    Results = results
};

Furthermore signature of Execute method has changed to:

ISearchResults Execute(QueryOptions options = null)

Do you have a working example for Umbraco 10? I'm also looking into this.

Greetings Johan

bjarnef commented 10 months ago

@JohanReitsma83 no, unfortunately not. I was looking into it, but found too much of the underlying API had changed in Examine v3.

However there a Examine v4 in beta, so I will recommend to try it out, which includes support for facets: https://github.com/Shazwazza/Examine/releases/tag/v4.0.0-beta.1

I have submitted a draft PR for Umbraco Commerce demostore to try out facets on ExternalIndex. https://github.com/umbraco/Umbraco.Commerce.DemoStore/pull/3

callumbwhyte commented 3 months ago

Hey everyone!

I am going to archiving the Examine Facets project now.

The native implementation in Examine v4+ is fantastic, and the team have done great work in documenting it all here: https://shazwazza.github.io/Examine/ This is my recommended solution going forward!

Thanks for all of your contributions!

Callum