title: How do I control the priority of nested queries in Sitecore ContentSearch with the Solr Provider?
body: <p><strong>Version Details:</strong> I am working with Sitecore 7.5 build 141003, using Solr v4.7 as the search engine/indexing server. I am also using the standard Sitecore Solr provider with no custom indexers.</p>
  
  <p><strong>Target Goal:</strong> 
  I am using Sitecore ContentSearch LINQ with PredicateBuilder to compile some flexible and nested queries. Currently, I need to search within a specific "Root item", while excluding templates with "folder" in their name, also excluding items with "/testing" in their path. At some point the "Root item" could be more than one item, and so could the path contains (currently just "/testing". In those cases, the idea is to use PredicateBuilder to build an outer "AND" predicate with inner "OR"s for the multiple "Root item"s and path exclusions.</p>
  
  <p><strong>Problem:</strong>
  At the moment, I am dealing with an issue regarding the order of nesting and priorities for these predicates/conditions. I have been testing several approaches and combinations, but the issue I keep running into is the !TemplateName.Contains and Item["_fullpath"].Contains being prioritized over the Paths.Contains, which ends up resulting in 0 results each time.</p>
  
  <p>I am using the Search.log to check the query output, and I have been manually testing against the Solr admin, running queries against it to compare results. Below, you will find examples of the combinations I have tried using Sitecore Linq, and the queries they produce for Solr.</p>
  
  <p><strong>Original Code Sample:</strong></p>
  
  <p><em>Original test with List for root items</em></p>
  
  <pre><code>// sometimes will be 1, sometimes will be multiple
  var rootItems = new List&lt;ID&gt; { pathID };  // simplified to 1 item for now
  var query = context.GetQueryable&lt;SearchResultItem&gt;();
  var folderFilter = PredicateBuilder.True&lt;SearchResultItem&gt;().And(i =&gt; !i.TemplateName.Contains("folder") &amp;&amp; !i["_fullpath"].Contains("/testing"));
  var pathFilter = PredicateBuilder.False&lt;SearchResultItem&gt;();
  pathFilter = rootItems.Aggregate(pathFilter, (current, id) =&gt; current.Or(i =&gt; i.Paths.Contains(id)));
  folderFilter = folderFilter.And(pathFilter);
  query.Filter(folderFilter).GetResults();
  </code></pre>
  
  <p><strong><em>Query output:</em></strong> (-_templatename:(*folder*) AND -_fullpath:(*/testing*)) AND _path:(730c169987a44ca7a9ce294ad7151f13)</p>
  
  <p>As you can see in the above output, there is an inner set of parenthesis around the two "not contains" filters which takes precedence over the Path one. When I run this exact query in the Solr admin, it returns 0 results. However, if I remove the inner parenthesis so it's all a single "AND" set, it returns the results expected.</p>
  
  <p>I tested this further with different combinations and approaches to the PredicateBuilder, and each combination results in the same query. I even tried adding two individual filters ("query.Filter(pred1).Filter(pred2)") to my main query object, and it results in the same output. </p>
  
  <p><strong>Additional Code Samples:</strong></p>
  
  <p><strong><em>Alt. 1</em></strong> - Adding "Paths.Contains" to folder filter directly</p>
  
  <pre><code>var query = context.GetQueryable&lt;SearchResultItem&gt;();
  var folderFilter = PredicateBuilder.True&lt;SearchResultItem&gt;().And(i =&gt; !i.TemplateName.Contains("folder") &amp;&amp; !i["_fullpath"].Contains("/testing"));
  folderFilter = folderFilter.And(i =&gt; i.Paths.Contains(pathID));
  query.Filter(folderFilter).GetResults();
  </code></pre>
  
  <p><strong><em>Query output:</em></strong> (-_templatename:(*folder*) AND -_fullpath:(*/testing*)) AND _path:(730c169987a44ca7a9ce294ad7151f13)</p>
  
  <p><strong><em>Alt 2</em></strong> - Two predicates joined to first</p>
  
  <pre><code>var query = context.GetQueryable&lt;SearchResultItem&gt;();
  var folderFilter = PredicateBuilder.True&lt;SearchResultItem&gt;().And(i =&gt; !i.TemplateName.Contains("folder") &amp;&amp; !i["_fullpath"].Contains("/testing"));
  var pathFilter = PredicateBuilder.False&lt;SearchResultItem&gt;().Or(i =&gt; i.Paths.Contains(pathID));
  folderFilter = folderFilter.And(pathFilter);
  query.Filter(folderFilter).GetResults();
  </code></pre>
  
  <p><strong><em>Query output:</em></strong> (-_templatename:(*folder*) AND -_fullpath:(*/testing*)) AND _path:(730c169987a44ca7a9ce294ad7151f13)</p>
  
  <p><strong><em>Alt 3</em></strong> - Two "inner" predicates, one for "Not"s and one for "Paths" joined to an outer predicate</p>
  
  <pre><code>var query = context.GetQueryable&lt;SearchResultItem&gt;();
  var folderFilter = PredicateBuilder.True&lt;SearchResultItem&gt;().And(i =&gt; !i.TemplateName.Contains("folder") &amp;&amp; !i["_fullpath"].Contains("/testing"));
  var pathFilter = PredicateBuilder.False&lt;SearchResultItem&gt;().Or(i =&gt; i.Paths.Contains(pathID));
  var finalPredicate = PredicateBuilder.True&lt;SearchResultItem&gt;().And(folderFilter).And(pathFilter);
  query.Filter(finalPredicate).GetResults();
  </code></pre>
  
  <p><strong><em>Query output:</em></strong> (-_templatename:(*folder*) AND -_fullpath:(*/testing*)) AND _path:(730c169987a44ca7a9ce294ad7151f13)</p>
  
  <p><strong>Conclusion:</strong>
  Ultimately, what I am looking for is a way to control the prioritization of these nested queries/conditions, or how I can build them to put the paths first, and the "Not" filters after. As mentioned, there are conditions where we will have multiple "Root items" and multiple path exclusions where I need to query something more like:</p>
  
  <blockquote>
    <p>(-_templatename:(*folder*) AND -_fullpath:(*/testing*) AND
    (_path:(730c169987a44ca7a9ce294ad7151f13) OR
    _path:(12c1aa7f60fa4e8d9f0a983bbbb40d8b)))</p>
  </blockquote>
  
  <p>OR</p>
  
  <blockquote>
    <p>(-_templatename:(*folder*) AND -_fullpath:(*/testing*) AND
    (_path:(730c169987a44ca7a9ce294ad7151f13)))</p>
  </blockquote>
  
  <p>Both of these queries return the results I expect/need when I run them directly in the Solr admin. However, I cannot seem to come up with an approach or order of operations using Sitecore ContentSearch Linq to output a query this way.</p>
  
  <p>Does anyone else have experience with how I can accomplish this? Depending on the suggestion, I am also willing to assemble this piece of the query without Sitecore Linq, if I can marry it back to the IQueryable for calling "GetFacets" and "GetResults".</p>
  
  <p><strong>Update:</strong>
  I didn't include all the revisions I have done because SO would probably kill me for how long this would get. That said, I did try one other slight variation on my original example (top) with a similar result as the others:</p>
  
  <pre><code>var folderFilter = PredicateBuilder.True&lt;SearchResultItem&gt;().And(i =&gt; !i.TemplateName.Contains("folder")).And(i =&gt; !i["_fullpath"].Contains("/testing"));
  var rootItems = new List&lt;ID&gt; { pathID, path2 };
  // or paths separately
  var pathFilter = PredicateBuilder.False&lt;SearchResultItem&gt;();
  pathFilter = rootItems.Aggregate(pathFilter, (current, id) =&gt; current.Or(i =&gt; i.Paths.Contains(id)));   
  var finalPredicate = folderFilter.And(pathFilter);
  var query = context.GetQueryable&lt;SearchResultItem&gt;();
  query.Filter(finalPredicate).GetResults();
  </code></pre>
  
  <p><strong><em>Query Output:</em></strong> ((-_templatename:(*folder*) AND -_fullpath:(*/testing*)) AND (_path:(730c169987a44ca7a9ce294ad7151f13) OR _path:(12c1aa7f60fa4e8d9f0a983bbbb40d8b)))</p>
  
  <p>And it's still those inner parenthesis around the "_templatename" and "_fullpath" conditions that causes problems.</p>
  
  <p>Thanks.</p>