Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nest Elasticsearch, combining bool query of Must and Should

I want to filter a group of documents by Year, Format and Content.

n pseudo-SQL:

SELECT * FROM /test/document
WHERE 
((format=f1|| format=f2||...|| format=fn) AND 
(Year!=2013 AND Year!=2015) AND 
(content like %c1% || content like %c2% ||...|| content like %cn%))

As you see, the number of formats and content items are dynamic and will be chosen by user. So far, I figured out how to make dynamic query for each field separately and then combine them using bool query like the code below;

// For YEAR
QueryContainer qYear=null;
    foreach (var year in years)
    {
        qYear |= new TermQuery() { Field = "year", Value = year };     
    }

// For FORMAT
 var qformat = new List<QueryContainer>();
 foreach (var format in txtDocs)
   {                    
     qformat.Add(Query<Document>.Match(m => m.OnField(p => p.Format).Query(format)));                
   }

  // For CONTENT
  var qc = new List<QueryContainer>();
   qc.Add(Query<Document>.Match(m => m.OnField(p => p.File).Query(discpString).Boost(2)));
    qc.Add(Query<Document>.Match(m => m.OnField(p => p.File).Query(roleString)));
    qc.Add(Query<Document>.Match(m => m.OnField(p => p.File).Query(taskString)));
    qc.Add(Query<Document>.Match(m => m.OnField(p => p.File).Query(sysString).Boost(2)));

//MY QUERY
 var searchResults = client.Search<Document>(s => s.Fields(f => f.Title, f => f.Format, f => f.Year, f => f.DateCreated, f => f.Id, f => f.Path, f => f.Size, f => f.Firstwords).
           Index(defaultIndex).From(0).Size(100).
           Query(q => q.Bool(b => b.MustNot(qYear).Should(qformat.ToArray()).Should(qc.ToArray()))));

When I run this code, the results for year and content field is what I expect but other formats that are not in the filtered list are also included! I want it to just retrieve those documents with the selected formats. Does anyone knows where is my mistake?

like image 877
Mahsa Avatar asked Feb 24 '16 10:02

Mahsa


1 Answers

I could find where was my mistake! I used Querycontainer for format in the same command as what I used for Year and then used Must in my query. Here is the changed part of the code:

 // For FORMAT
 QueryContainer qF=null;
 foreach (var format in txtDocs)
 {
     qF |= new TermQuery()
     { 
         Field = "format", 
         Value = format 
     }; 
 }

//MY QUERY
var searchResults = client.Search<Document>(s => s
     .Fields(
        f => f.Title, 
        f => f.Format, 
        f => f.Year, 
        f => f.DateCreated, 
        f => f.Id, 
        f => f.Path, 
        f => f.Size, 
        f => f.Firstwords)
    .Index(defaultIndex)
    .From(0)
    .Size(100)
    .Query(q => q
       .Bool(b => b.MustNot(qYear)
       .Must(qF)
       .Should(qc.ToArray())
     )
);
like image 91
Mahsa Avatar answered Oct 14 '22 21:10

Mahsa