Package com.flaptor.indextank.blender

Source Code of com.flaptor.indextank.blender.BlendingQueryMatcher

/*
* Copyright (c) 2011 LinkedIn, Inc
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/

package com.flaptor.indextank.blender;

import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;

import com.flaptor.indextank.index.DocId;
import com.flaptor.indextank.index.QueryMatcher;
import com.flaptor.indextank.index.ScoredMatch;
import com.flaptor.indextank.index.TopMatches;
import com.flaptor.indextank.index.results.SimpleScoredDocIds;
import com.flaptor.indextank.index.scorer.FacetingManager;
import com.flaptor.indextank.query.Query;
import com.flaptor.util.CollectionsUtil;
import com.flaptor.util.Execute;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Multiset;
import com.google.common.collect.Sets;

/**
* A BlendingQueryMatcher is created based on two internal matchers. One of
* them should be static and provide older results and the other one should
* be fresher and its results will be considered true over the old ones.
* <br><br>
* This matcher will merge results from both searchers and will prioritize
* the current results. Any result with changes in the newer matcher will
* be ignored in the older matcher. 
*
* @author Santiago Perez (santip)
*/
public class BlendingQueryMatcher implements QueryMatcher {
    private static final Logger logger = Logger.getLogger(Execute.whoAmI());

  private final QueryMatcher historySearcher;
  private final QueryMatcher currentSearcher;

    /**
     * Constructor.
     */
  public BlendingQueryMatcher(QueryMatcher history, QueryMatcher current) {
    this.historySearcher = history;
    this.currentSearcher = current;
  }
 
  @Override
  public TopMatches findMatches(Query query, Predicate<DocId> docFilter, int limit, int scoringFunctionIndex) throws InterruptedException {
    Predicate<DocId> historyFilter = notModified(currentSearcher, docFilter);
   
        /* instrumentation */ long historyStart = System.currentTimeMillis();
   
        TopMatches history = historySearcher.findMatches(query, historyFilter, limit, scoringFunctionIndex);
    int historyMatches = history.getTotalMatches();
   
    /* instrumentation */ long currentStart = System.currentTimeMillis();
   
        TopMatches current = docFilter == null ? currentSearcher.findMatches(query, limit, scoringFunctionIndex) : currentSearcher.findMatches(query, docFilter, limit, scoringFunctionIndex);
    int currentMatches = current.getTotalMatches();

    /* instrumentation */ long endSearch = System.currentTimeMillis();
   
    List<ScoredMatch> currentResults = Lists.newArrayList(current);
   
    Iterable<ScoredMatch> historyResults = filterIds(history, getIds(currentResults));
    List<ScoredMatch> results = mergeIntoList(currentResults, historyResults, limit);
        int matches = Math.abs(currentMatches) + Math.abs(historyMatches);
    if (results.size() < limit) {
      matches = results.size();
    }
   
    if (currentMatches < 0 || historyMatches < 0) {
        matches = -matches;
    }
   
    /* instrumentation */  long end = System.currentTimeMillis();
   
        logger.debug("(Search) historic searcher took: " + (currentStart - historyStart) + " ms., current searcher took: " +
                + (endSearch - currentStart) + " ms., merge took: " + (end - endSearch) + " ms.");
       
        Map<String, Multiset<String>> facets = FacetingManager.mergeFacets(history.getFacetingResults(), current.getFacetingResults());
       
    return new SimpleScoredDocIds(results, limit, matches, facets);
  }

  public TopMatches findMatches(Query query, int limit, int scoringFunctionIndex) throws InterruptedException {
    return findMatches(query, null, limit, scoringFunctionIndex);
  }
 
  @Override
  public boolean hasChanges(DocId docid) throws InterruptedException {
    return historySearcher.hasChanges(docid) || currentSearcher.hasChanges(docid);
  }
 
  private static Set<DocId> getIds(List<ScoredMatch> currentResults) {
    return Sets.newHashSet(Iterables.transform(currentResults, ScoredMatch.DOC_ID_FUNCTION));
  }
 
  private static List<ScoredMatch> mergeIntoList(Iterable<ScoredMatch> a, Iterable<ScoredMatch> b, int limit) {
    Iterable<ScoredMatch> merged = CollectionsUtil.mergeIterables(ImmutableList.of(a, b));
    return Lists.newArrayList(merged);
  }

  private static Iterable<ScoredMatch> filterIds(Iterable<ScoredMatch> results, final Set<DocId> ids) {
    return Iterables.filter(results, new Predicate<ScoredMatch>() {
      @Override
      public boolean apply(ScoredMatch r) {
        return !ids.contains(r.getDocId());
      }
    });
  }

  private static Predicate<DocId> notModified(final QueryMatcher s, final Predicate<DocId> andFilter) {
    return new Predicate<DocId>() {
      @Override
      public boolean apply(DocId docid) {
                try {
                    return !s.hasChanges(docid) && (andFilter == null || andFilter.apply(docid)) ;
                } catch (InterruptedException e) {
                    return false;
                }
      }
    };
  }

    @Override
    public int countMatches(Query query) throws InterruptedException {
        return countMatches(query, null);
    }

    @Override
    public int countMatches(Query query, Predicate<DocId> idFilter) throws InterruptedException {
        Predicate<DocId> historyFilter = notModified(currentSearcher, idFilter);
       
        int count = historySearcher.countMatches(query, historyFilter);
       
        if (idFilter == null) {
            count += currentSearcher.countMatches(query);
        } else {
            count += currentSearcher.countMatches(query, idFilter);
        }
        return count;
    }


}
TOP

Related Classes of com.flaptor.indextank.blender.BlendingQueryMatcher

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.