private void handleFilterExclusions() throws IOException {
    List<String> excludeTags = freq.domain.excludeTags;

    if (excludeTags == null || excludeTags.size() == 0) {
      return;
    }

    // TODO: somehow remove responsebuilder dependency
    ResponseBuilder rb = SolrRequestInfo.getRequestInfo().getResponseBuilder();
    Map tagMap = (Map) rb.req.getContext().get("tags");
    if (tagMap == null) {
      // no filters were tagged
      return;
    }

    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);
        }
      }
    }
    if (excludeSet.size() == 0) return;

    List<Query> qlist = new ArrayList<>();

    // add the base query
    if (!excludeSet.containsKey(rb.getQuery())) {
      qlist.add(rb.getQuery());
    }

    // add the filters
    if (rb.getFilters() != null) {
      for (Query q : rb.getFilters()) {
        if (!excludeSet.containsKey(q)) {
          qlist.add(q);
        }
      }
    }

    // now walk back up the context tree
    // TODO: we lose parent exclusions...
    for (FacetContext curr = fcontext; curr != null; curr = curr.parent) {
      if (curr.filter != null) {
        qlist.add(curr.filter);
      }
    }

    // recompute the base domain
    fcontext.base = fcontext.searcher.getDocSet(qlist);
  }
  /**
   * factory method for invoking json facet framework as whole. Note: this is currently only used
   * from SimpleFacets, not from JSON Facet API itself.
   */
  public static FacetProcessor<?> createProcessor(
      SolrQueryRequest req, Map<String, Object> params, DocSet docs) {
    FacetParser parser = new FacetTopParser(req);
    FacetRequest facetRequest = null;
    try {
      facetRequest = parser.parse(params);
    } catch (SyntaxError syntaxError) {
      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, syntaxError);
    }

    FacetContext fcontext = new FacetContext();
    fcontext.base = docs;
    fcontext.req = req;
    fcontext.searcher = req.getSearcher();
    fcontext.qcontext = QueryContext.newContext(fcontext.searcher);

    return facetRequest.createFacetProcessor(fcontext);
  }
Exemple #3
0
  /**
   * @param filter The filter for the bucket that resulted in this context/domain. Can be null if
   *     this is the root context.
   * @param domain The resulting set of documents for this facet.
   */
  public FacetContext sub(Query filter, DocSet domain) {
    FacetContext ctx = new FacetContext();
    ctx.parent = this;
    ctx.base = domain;
    ctx.filter = filter;

    // carry over from parent
    ctx.flags = flags;
    ctx.qcontext = qcontext;
    ctx.req = req;
    ctx.searcher = searcher;

    return ctx;
  }
  private void handleDomainChanges() throws IOException {
    if (freq.domain == null) return;
    handleFilterExclusions();

    // Check filters... if we do have filters they apply after domain changes.
    // We still calculate them first because we can use it in a parent->child domain change.
    evalFilters();

    boolean appliedFilters = handleBlockJoin();

    if (this.filter != null && !appliedFilters) {
      fcontext.base = fcontext.base.intersection(filter);
    }
  }
  void processSubs(SimpleOrderedMap<Object> response, Query filter, DocSet domain)
      throws IOException {

    // TODO: what if a zero bucket has a sub-facet with an exclusion that would yield results?
    // should we check for domain-altering exclusions, or even ask the sub-facet for
    // it's domain and then only skip it if it's 0?

    if (domain == null || domain.size() == 0 && !freq.processEmpty) {
      return;
    }

    for (Map.Entry<String, FacetRequest> sub : freq.getSubFacets().entrySet()) {
      // make a new context for each sub-facet since they can change the domain
      FacetContext subContext = fcontext.sub(filter, domain);
      FacetProcessor subProcessor = sub.getValue().createFacetProcessor(subContext);
      if (fcontext.getDebugInfo()
          != null) { // if fcontext.debugInfo != null, it means rb.debug() == true
        FacetDebugInfo fdebug = new FacetDebugInfo();
        subContext.setDebugInfo(fdebug);
        fcontext.getDebugInfo().addChild(fdebug);

        fdebug.setReqDescription(sub.getValue().getFacetDescription());
        fdebug.setProcessor(subProcessor.getClass().getSimpleName());
        if (subContext.filter != null) fdebug.setFilter(subContext.filter.toString());

        final RTimer timer = new RTimer();
        subProcessor.process();
        long timeElapsed = (long) timer.getTime();
        fdebug.setElapse(timeElapsed);
        fdebug.putInfoItem("domainSize", (long) subContext.base.size());
      } else {
        subProcessor.process();
      }

      response.add(sub.getKey(), subProcessor.getResponse());
    }
  }
  // returns "true" if filters were applied to fcontext.base already
  private boolean handleBlockJoin() throws IOException {
    boolean appliedFilters = false;
    if (!(freq.domain.toChildren || freq.domain.toParent)) return appliedFilters;

    // TODO: avoid query parsing per-bucket somehow...
    String parentStr = freq.domain.parents;
    Query parentQuery;
    try {
      QParser parser = QParser.getParser(parentStr, fcontext.req);
      parentQuery = parser.getQuery();
    } catch (SyntaxError err) {
      throw new SolrException(
          SolrException.ErrorCode.BAD_REQUEST,
          "Error parsing block join parent specification: " + parentStr);
    }

    BitDocSet parents = fcontext.searcher.getDocSetBits(parentQuery);
    DocSet input = fcontext.base;
    DocSet result;

    if (freq.domain.toChildren) {
      // If there are filters on this facet, then use them as acceptDocs when executing toChildren.
      // We need to remember to not redundantly re-apply these filters after.
      DocSet acceptDocs = this.filter;
      if (acceptDocs == null) {
        acceptDocs = fcontext.searcher.getLiveDocs();
      } else {
        appliedFilters = true;
      }
      result = BlockJoin.toChildren(input, parents, acceptDocs, fcontext.qcontext);
    } else {
      result = BlockJoin.toParents(input, parents, fcontext.qcontext);
    }

    fcontext.base = result;
    return appliedFilters;
  }