dsmiley commented on code in PR #1154:
URL: https://github.com/apache/solr/pull/1154#discussion_r1014458212


##########
solr/core/src/java/org/apache/solr/handler/component/QueryElevationComponent.java:
##########
@@ -590,52 +592,79 @@ private void setFilters(ResponseBuilder rb, Elevation 
elevation) {
       return;
     }
 
-    Map<?, ?> tagMap = (Map<?, ?>) rb.req.getContext().get("tags");
-    if (tagMap == null) {
+    Set<Query> excludeSet = getTaggedQueries(rb, excludeTags);
+    if (excludeSet.isEmpty()) {
       // no filters were tagged
       return;
     }
 
-    // TODO: this code is copied from FacetProcessor#handleFilterExclusions()
-    // duplication could be avoided by placing this code in a common utility 
method, perhaps in
-    // QueryUtils
-    IdentityHashMap<Query, Boolean> excludeSet = new IdentityHashMap<>();
-    for (String excludeTag : excludeTags) {
-      Object olst = tagMap.get(excludeTag);
-      // tagMap has entries of List<String,List<QParser>>, but subject to 
change in the future
-      if (!(olst instanceof Collection)) continue;
-      for (Object o : (Collection<?>) olst) {
-        if (!(o instanceof QParser)) continue;
-        QParser qp = (QParser) o;
-        try {
-          excludeSet.put(qp.getQuery(), Boolean.TRUE);
-        } catch (SyntaxError syntaxError) {
-          // This should not happen since we should only be retrieving a 
previously parsed query
-          throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, 
syntaxError);
-        }
-      }
-    }
-
     List<Query> updatedFilters = new ArrayList<Query>();
 
-    for (Query q : filters) {
-      if (!excludeSet.containsKey(q) || q instanceof 
CollapsingQParserPlugin.CollapsingPostFilter) {
-        updatedFilters.add(q);
+    for (Query filter : filters) {
+      if (!excludeSet.contains(filter) || filter instanceof PostFilter) {
+        updatedFilters.add(filter);
         continue;
       }
 
       // we're looking at a filter that has been tagged for exclusion
       // transform it into a boolean OR of the original filter with the 
"include query" matching the
       // elevated docs
       BooleanQuery.Builder queryBuilder = new BooleanQuery.Builder();
-      queryBuilder.add(q, BooleanClause.Occur.SHOULD);
+      queryBuilder.add(filter, BooleanClause.Occur.SHOULD);

Review Comment:
   As I think about this more... the original "filter" (a "fq" param) should 
probably be wrapped in FilterQuery _if it's configured to cache_, this way 
what's being cached is just this filter, and thus would be more likely to get a 
good cache hit rate.  We'd set the BooleanQuery combo to not cache; it'll be 
fast -- one of its components is already cached and the other is a trivial set 
of documents pre-selected -- fast.  If multiple queries come in with the same 
filter queries, they will use the same cache entries, even if only some hit 
certain QEC rules.



##########
solr/core/src/java/org/apache/solr/handler/component/QueryElevationComponent.java:
##########
@@ -590,52 +592,79 @@ private void setFilters(ResponseBuilder rb, Elevation 
elevation) {
       return;
     }
 
-    Map<?, ?> tagMap = (Map<?, ?>) rb.req.getContext().get("tags");
-    if (tagMap == null) {
+    Set<Query> excludeSet = getTaggedQueries(rb, excludeTags);
+    if (excludeSet.isEmpty()) {
       // no filters were tagged
       return;
     }
 
-    // TODO: this code is copied from FacetProcessor#handleFilterExclusions()
-    // duplication could be avoided by placing this code in a common utility 
method, perhaps in
-    // QueryUtils
-    IdentityHashMap<Query, Boolean> excludeSet = new IdentityHashMap<>();
-    for (String excludeTag : excludeTags) {
-      Object olst = tagMap.get(excludeTag);
-      // tagMap has entries of List<String,List<QParser>>, but subject to 
change in the future
-      if (!(olst instanceof Collection)) continue;
-      for (Object o : (Collection<?>) olst) {
-        if (!(o instanceof QParser)) continue;
-        QParser qp = (QParser) o;
-        try {
-          excludeSet.put(qp.getQuery(), Boolean.TRUE);
-        } catch (SyntaxError syntaxError) {
-          // This should not happen since we should only be retrieving a 
previously parsed query
-          throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, 
syntaxError);
-        }
-      }
-    }
-
     List<Query> updatedFilters = new ArrayList<Query>();
 
-    for (Query q : filters) {
-      if (!excludeSet.containsKey(q) || q instanceof 
CollapsingQParserPlugin.CollapsingPostFilter) {
-        updatedFilters.add(q);
+    for (Query filter : filters) {
+      if (!excludeSet.contains(filter) || filter instanceof PostFilter) {

Review Comment:
   Again on this PostFilter issue... assuming this is your logic and not simply 
taking it from somewhere else... what situation caused you to add this?  
Depending on how the PostFilter is implemented, it may or may not be possible 
to have the QEC slip docs past it like it can others.  In such a scenario, we 
should probably give the user an error because we can't, instead of silently 
ignoring that they asked to ignore this tagged filter but we actually won't.



##########
solr/core/src/java/org/apache/solr/handler/component/QueryElevationComponent.java:
##########
@@ -590,52 +592,79 @@ private void setFilters(ResponseBuilder rb, Elevation 
elevation) {
       return;
     }
 
-    Map<?, ?> tagMap = (Map<?, ?>) rb.req.getContext().get("tags");
-    if (tagMap == null) {
+    Set<Query> excludeSet = getTaggedQueries(rb, excludeTags);
+    if (excludeSet.isEmpty()) {
       // no filters were tagged
       return;
     }
 
-    // TODO: this code is copied from FacetProcessor#handleFilterExclusions()
-    // duplication could be avoided by placing this code in a common utility 
method, perhaps in
-    // QueryUtils
-    IdentityHashMap<Query, Boolean> excludeSet = new IdentityHashMap<>();
-    for (String excludeTag : excludeTags) {
-      Object olst = tagMap.get(excludeTag);
-      // tagMap has entries of List<String,List<QParser>>, but subject to 
change in the future
-      if (!(olst instanceof Collection)) continue;
-      for (Object o : (Collection<?>) olst) {
-        if (!(o instanceof QParser)) continue;
-        QParser qp = (QParser) o;
-        try {
-          excludeSet.put(qp.getQuery(), Boolean.TRUE);
-        } catch (SyntaxError syntaxError) {
-          // This should not happen since we should only be retrieving a 
previously parsed query
-          throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, 
syntaxError);
-        }
-      }
-    }
-
     List<Query> updatedFilters = new ArrayList<Query>();
 
-    for (Query q : filters) {
-      if (!excludeSet.containsKey(q) || q instanceof 
CollapsingQParserPlugin.CollapsingPostFilter) {
-        updatedFilters.add(q);
+    for (Query filter : filters) {
+      if (!excludeSet.contains(filter) || filter instanceof PostFilter) {
+        updatedFilters.add(filter);
         continue;
       }
 
       // we're looking at a filter that has been tagged for exclusion
       // transform it into a boolean OR of the original filter with the 
"include query" matching the
       // elevated docs
       BooleanQuery.Builder queryBuilder = new BooleanQuery.Builder();
-      queryBuilder.add(q, BooleanClause.Occur.SHOULD);
+      queryBuilder.add(filter, BooleanClause.Occur.SHOULD);
       queryBuilder.add(elevation.includeQuery, BooleanClause.Occur.SHOULD);
-      updatedFilters.add(queryBuilder.build());
+      BooleanQuery updatedFilter = queryBuilder.build();
+
+      if (!(filter instanceof ExtendedQuery)) {
+        updatedFilters.add(updatedFilter);
+      } else {
+        // if the original filter had the Local Param "cache" and/or "cost", 
it will be an
+        // ExtendedQuery;
+        // in this case, the updated filter should be wrapped with the same 
cache and cost settings
+        ExtendedQuery eq = (ExtendedQuery) filter;
+        WrappedQuery wrappedUpdatedFilter = new WrappedQuery(updatedFilter);
+        wrappedUpdatedFilter.setCache(eq.getCache());
+        wrappedUpdatedFilter.setCost(eq.getCost());

Review Comment:
   FYI @risdenk RE immutability of all Query classes.  Maybe this slips past us 
for now but it'll have to change.



##########
solr/solrj/src/java/org/apache/solr/common/params/QueryElevationParams.java:
##########
@@ -59,4 +59,11 @@ public interface QueryElevationParams {
    * set this to true. False by default.
    */
   String ELEVATE_ONLY_DOCS_MATCHING_QUERY = "elevateOnlyDocsMatchingQuery";
+
+  /**
+   * By default, the component respects the fq parameter. If you want to 
elevate documents that do
+   * not match the provided filters, tag the filters in question via the local 
parameter syntax
+   * fq={!tag=t1}field1:value1 and then specify the tags for exclusion via 
elevate.excludeTag=t1

Review Comment:
   ```suggestion
      * fq={!tag=t1}field1:value1 and then specify the tags for exclusion via 
elevate.excludeTags=t1
   ```



##########
solr/solr-ref-guide/modules/query-guide/pages/query-elevation-component.adoc:
##########
@@ -234,5 +234,18 @@ 
http://localhost:8983/solr/techproducts/elevate?q=ipod&df=text&elevateIds=IW-02,
 
 === The fq Parameter with Elevation
 
-Query elevation respects the standard filter query (`fq`) parameter.
+By default, query elevation respects the standard filter query (`fq`) 
parameter.
 That is, if the query contains the `fq` parameter, all results will be within 
that filter even if `elevate.xml` adds other documents to the result set.
+
+If you want elevated documents to be included in the result set whether or not 
they match specific filter queries, you can tag those filter queries using 
xref:local-params.adoc[LocalParams syntax] and then specify the tags for 
exclusion via the `elevate.excludeTags` request parameter.
+Both the `tag` local param and the `elevate.excludeTags` request parameter may 
specify multiple values by separating them with commas.
+
+[source,text]
+q=mainquery&fq=status:public&fq={!tag=dt}doctype:pdf&elevate.excludeTags=dt
+
+[source,text]
+q=mainquery&fq=status:public&fq={!tag=t1,t2}a:b&fq={!tag=t3}c:d&fq={!tag=t4}e:f&elevate.excludeTags=t1,t4
+
+When a filter is tagged for exclusion, it is not ignored completely; rather it 
is modified so that the elevated documents can pass through.
+Documents that are not elevated are still subject to the filter.
+This feature may have a performance impact when filter caching is enabled and 
the modified filters are not found in the cache.

Review Comment:
   This last line will no longer be needed to say once we use `FilterQuery` as 
I suggest.



##########
solr/solrj/src/java/org/apache/solr/common/params/QueryElevationParams.java:
##########
@@ -59,4 +59,11 @@ public interface QueryElevationParams {
    * set this to true. False by default.
    */
   String ELEVATE_ONLY_DOCS_MATCHING_QUERY = "elevateOnlyDocsMatchingQuery";
+
+  /**
+   * By default, the component respects the fq parameter. If you want to 
elevate documents that do
+   * not match the provided filters, tag the filters in question via the local 
parameter syntax
+   * fq={!tag=t1}field1:value1 and then specify the tags for exclusion via 
elevate.excludeTag=t1

Review Comment:
   It's sad this component didn't use a common prefix naming standard like the 
other components; ah well.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to