Orchard Lucene Custom Search Service with Query Grouping and Numeric Range Query

369 views Asked by At

I'm trying to implement my own custom SearchService. As I understand it

// If I wanted to query "+name:camera +price:[100 TO 150] +location:thailand"
searchBuilder.WithField("name", "camera").ExactMatch().Mandatory();
searchBuilder.WithinRange("price", 100, 150, true, true).Mandatory();
searchBuilder.WithField("location", "thailand").ExactMatch().Mandatory();

No problem here. But how do I approach a query with grouping (clauses with parentheses)?

// How do I query "+name:camera +(price:[100 TO 150] cost:[100 TO 150]) +(bundle-price:[100 TO 150] total-price:[100 TO 150])"?
// Since the ISearchBuilder interface doesn't support grouping, the only other way
// I could think of is to use the freestyle ISearchBuilder.Parse() to construct the query.
// However this doesn't return any hits:
searchBuilder.WithField("name", "camera").ExactMatch().Mandatory();
searchBuilder.Parse("price", "[100 TO 150] cost:[100 TO 150]", false).Mandatory();
searchBuilder.Parse("bundle-price", "[100 TO 150] total-price:[100 TO 150]", false).Mandatory();

There's just isn't enough information for ISearchBuilder.Parse() to determine the datatype of the range (whether it's int, float or double). Looks like Luke is having this problem too which can be circumvented using XML Query Parser that I don't think Lucene.Net has:

Lucene numeric range search with LUKE


I was thinking that if the ISearchBuilder has a method to allow us to insert our own Query

// /src/Orchard/Indexing/ISearchBuider.cs
public interface ISearchBuilder {
    ISearchBuilder WithQuery(Query query);
}

// /src/Orchard.Web/Modules/Lucene/Services/LuceneSearchBuilder.cs
public class LuceneSearchBuilder : ISearchBuilder {
    public ISearchBuilder WithQuery(Query query) {
        CreatePendingClause();
        _query = query;
        return this;
    }
}

public class CustomSearchService {
    public void Search() {
        // construct our own custom queries
        var booleanQuery1 = new BooleanQuery();
        booleanQuery1.Add(NumericRangeQuery.NewDoubleRange("price", 100, 150, true, true), Occur.SHOULD);
        booleanQuery1.Add(NumericRangeQuery.NewDoubleRange("cost", 100, 150, true, true), Occur.SHOULD);

        var booleanQuery2 = new BooleanQuery();
        booleanQuery2.Add(NumericRangeQuery.NewDoubleRange("bundle-price", 100, 150, true, true), Occur.SHOULD);
        booleanQuery2.Add(NumericRangeQuery.NewDoubleRange("total-price", 100, 150, true, true), Occur.SHOULD);

        searchBuilder.WithField("name", "camera").ExactMatch().Mandatory();
        // insert our custom queries into the SearchBuilder using the newly added interface method (ISearchBuilder.WithQuery()) above
        searchBuilder.WithQuery(booleanQuery1).Mandatory();
        searchBuilder.WithQuery(booleanQuery2).Mandatory();
    }
}

then we can construct more complex and flexible queries.

Update

Someone has raised this issue before at https://github.com/OrchardCMS/Orchard/issues/5764

1

There are 1 answers

1
urbanit On

You probably should use Search API with facets. Here is an exact presentation: https://www.youtube.com/watch?v=7v5qSR4g7E0 and some notes here: http://weblogs.asp.net/bleroy/orchard-harvest-2015-search-api