0
votes

I have a Lucene.net index with a search that applies multiple queries:

BooleanQuery filterQuery = new BooleanQuery();

if (searchDto.SubCategoryId != Guid.Empty)
{
    TermQuery tq = new TermQuery(new Term("SubCategoryId", searchDto.SubCategoryId.ToString()));
    filterQuery.Add(tq, Occur.MUST);
}

if (!string.IsNullOrEmpty(searchDto.SearchPhrase))
{
    var parser = new MultiFieldQueryParser
      (Version.LUCENE_30, new[] { "Title", "Description", "SubCategoryName", "LongDescription" }, analyzer);
    var query = parseQuery(searchDto.SearchPhrase, parser);
    filterQuery.Add(query, Occur.MUST);
}

topDocs = searcher.Search(filterQuery, null, hits_limit);

This works great. For instance, it would only match a subcategory if I pass it a subcategory Id. However, how do I formulate a query that would match not based on whether I send it a filter value, but based on whether an index record has a value for one of it's fields.

For instance, one of the lucene index record fields is IsBundle. Now, if IsBundle is true, I want the record if RelationshipId matches the searchDto.RelationshipId I send it. If IsBundle is false, I don't care about RelationshipId. So my end result would be some combination of records where the IsBundle is true and the RelationshipId matches my searchDto.RelationshipId and where IsBundle is false

2

2 Answers

2
votes

If you collapse the logic, isn't this just the equivalent of

IsBundle==false OR RelationshipID==x

or

var q = new BooleanQuery();
q.Add(new TermQuery(new Term("IsBundle", "true"), Occur.SHOULD);
q.Add(new TermQuery(new Term("RelationshipID", dto.thing), Ocurr.SHOULD);
1
votes

Without having specifics regarding the index field RelationshipID, I'll assume RelationshipID is a string type.

If searchDto.RelationshipID is specified you want

(RelationshipID:{searchDto.RelationshipID} AND IsBundle:true) OR IsBundle:false

If searchDto.RelationshipID is not given

IsBundle:false

This code adds the appropriate query to filterQuery.

if (!String.IsNullOrEmpty(searchDto.RelationshipID))
{
    BooleanQuery q = new BooleanQuery();
    q.Add(new BooleanClause(
        new TermQuery(new Term("RelationshipId", searchDto.RelationshipID)), Occur.MUST)
        );
    q.Add(new BooleanClause(
        new TermQuery(new Term("IsBundle", "true")), Occur.MUST)
        );
    BooleanClause clause = new BooleanClause(q, Occur.SHOULD);
    q = new BooleanQuery();
    q.Add(clause);
    q.Add(new BooleanClause(
                        new TermQuery(new Term("IsBundle", "false")), Occur.SHOULD)
                        );                
    filterQuery.Add(q,Occur.MUST);            
}
else
{
    filterQuery.Add(new BooleanClause(
        new TermQuery(new Term("IsBundle", "false")), Occur.MUST)
        );
}

There may be an elegant way to assemble the query but this satisfies the requirement.