AnnotationQuery.java

  1. /*
  2.  *  AnnotationQuery.java
  3.  *
  4.  *  Copyright (c) 2007-2011, The University of Sheffield.
  5.  *
  6.  *  This file is part of GATE Mímir (see http://gate.ac.uk/family/mimir.html),
  7.  *  and is free software, licenced under the GNU Lesser General Public License,
  8.  *  Version 3, June 2007 (also included with this distribution as file
  9.  *  LICENCE-LGPL3.html).
  10.  *
  11.  *  Valentin Tablan, 4 Mar 2009
  12.  *
  13.  *  $Id: AnnotationQuery.java 17236 2014-01-17 15:31:02Z valyt $
  14.  */
  15. package gate.mimir.search.query;


  16. import gate.mimir.Constraint;
  17. import gate.mimir.ConstraintType;
  18. import gate.mimir.SemanticAnnotationHelper;
  19. import gate.mimir.search.QueryEngine;
  20. import gate.mimir.search.terms.AnnotationTermsQuery;
  21. import gate.mimir.search.terms.TermsResultSet;
  22. import it.unimi.di.big.mg4j.index.Index;
  23. import it.unimi.di.big.mg4j.search.visitor.DocumentIteratorVisitor;
  24. import it.unimi.dsi.fastutil.objects.ReferenceSet;
  25. import it.unimi.dsi.fastutil.objects.ReferenceSets;

  26. import java.io.IOException;
  27. import java.util.ArrayList;
  28. import java.util.HashMap;
  29. import java.util.List;
  30. import java.util.Map;

  31. import org.slf4j.Logger;
  32. import org.slf4j.LoggerFactory;


  33. /**
  34.  * A query for the annotations index.
  35.  */
  36. public class AnnotationQuery implements QueryNode {

  37.   private static final long serialVersionUID = 5996543707885867821L;


  38.   public static class AnnotationQueryExecutor extends AbstractQueryExecutor{

  39.    
  40.     /**
  41.      * @param engine
  42.      * @param query
  43.      */
  44.     public AnnotationQueryExecutor(AnnotationQuery query, QueryEngine engine) throws IOException {
  45.       super(engine, query);
  46.       this.query = query;
  47.       buildQuery();
  48.     }
  49.    
  50.     /**
  51.      * The query being executed.
  52.      */
  53.     private AnnotationQuery query;
  54.    
  55.     /**
  56.      * Logger for this class.
  57.      */
  58.     private static Logger logger = LoggerFactory.getLogger(AnnotationQueryExecutor.class);

  59.     /**
  60.      * The underlying OrQuery executor that actually does the work.
  61.      */
  62.     private QueryExecutor underlyingExecutor;
  63.    
  64.     private transient boolean isInDocumentMode;
  65.    
  66.     /**
  67.      * Build the underlying OrQuery executor that this annotation query uses.
  68.      */
  69.     protected void buildQuery() throws IOException {
  70.       SemanticAnnotationHelper helper = engine.getAnnotationHelper(query);
  71.       isInDocumentMode = (helper.getMode() ==
  72.           SemanticAnnotationHelper.Mode.DOCUMENT);
  73.       // get the mention URIs
  74.       TermsResultSet trs = new AnnotationTermsQuery(query).execute(engine);
  75.       if(trs.termStrings != null && trs.termStrings.length > 0 &&
  76.          trs.termLengths != null) {
  77.         QueryNode[] disjuncts = new QueryNode[trs.termStrings.length];
  78.         for(int index = 0; index < trs.termStrings.length; index++) {
  79.           // create a term query for the mention URI
  80.           disjuncts[index] = new TermQuery(query.annotationType,
  81.               trs.termStrings[index], trs.termLengths[index]);
  82.         }
  83.         QueryNode underlyingQuery = new OrQuery(disjuncts);
  84.         underlyingExecutor = underlyingQuery.getQueryExecutor(engine);        
  85.       } else {
  86.         // no results from the helper => no results from us
  87.         latestDocument = -1;
  88.       }
  89.     }
  90.    
  91.    
  92.     /* (non-Javadoc)
  93.      * @see gate.mimir.search.query.QueryExecutor#close()
  94.      */
  95.     public void close() throws IOException {
  96.       if(closed) return;
  97.       super.close();
  98.       if(underlyingExecutor != null) underlyingExecutor.close();
  99.     }

  100.     /* (non-Javadoc)
  101.      * @see gate.mimir.search.query.QueryExecutor#getLatestDocument()
  102.      */
  103.     public long getLatestDocument() {
  104.       if(closed || latestDocument == -1) return -1;
  105.       return underlyingExecutor.getLatestDocument();
  106.     }

  107.     /* (non-Javadoc)
  108.      * @see gate.mimir.search.query.QueryExecutor#nextDocument(int)
  109.      */
  110.     public long nextDocument(long greaterThan) throws IOException {
  111.       if(closed || latestDocument == -1) return -1;
  112.       return latestDocument = underlyingExecutor.nextDocument(greaterThan);
  113.     }

  114.     /* (non-Javadoc)
  115.      * @see gate.mimir.search.query.QueryExecutor#nextHit()
  116.      */
  117.     public Binding nextHit() throws IOException {
  118.       if(closed || latestDocument == -1) return null;
  119.       Binding underlyingHit = underlyingExecutor.nextHit();
  120.       if(underlyingHit == null) return null;
  121.       long doc = underlyingHit.getDocumentId();
  122.       if(isInDocumentMode) {
  123.         return new Binding(query, doc, 0, engine.getIndex().getDocumentSize(doc),
  124.           null);
  125.       } else {
  126.         return new Binding(query, doc,
  127.           underlyingHit.getTermPosition(),
  128.           underlyingHit.getLength(),
  129.           null);
  130.       }
  131.     }
  132.    
  133.     @Override
  134.     public ReferenceSet<Index> indices() {
  135.       if(underlyingExecutor != null) {
  136.         return underlyingExecutor.indices();
  137.       } else {
  138.         return ReferenceSets.EMPTY_SET;
  139.       }
  140.     }
  141.    
  142.     public <T> T accept( final DocumentIteratorVisitor<T> visitor ) throws IOException {
  143.       if(underlyingExecutor == null) return null;
  144.       if ( ! visitor.visitPre( this ) ) return null;
  145.       final T[] a = visitor.newArray( 1 );
  146.       if ( a == null ) {
  147.         if ( underlyingExecutor.accept( visitor ) == null ) return null;
  148.       }
  149.       else {
  150.         if ( ( a[ 0 ] = underlyingExecutor.accept( visitor ) ) == null ) return null;
  151.       }
  152.       return visitor.visitPost( this, a );
  153.     }

  154.     public <T> T acceptOnTruePaths( final DocumentIteratorVisitor<T> visitor ) throws IOException {
  155.       if(underlyingExecutor == null) return null;
  156.       if ( ! visitor.visitPre( this ) ) return null;
  157.       final T[] a = visitor.newArray( 1 );
  158.       if ( a == null ) {
  159.         if ( underlyingExecutor.acceptOnTruePaths( visitor ) == null ) return null;    
  160.       }
  161.       else {
  162.         if ( ( a[ 0 ] = underlyingExecutor.acceptOnTruePaths( visitor ) ) == null ) return null;
  163.       }
  164.       return visitor.visitPost( this, a );
  165.     }
  166.   }
  167.  
  168.   /**
  169.    * Constructs a new {@link AnnotationQuery}.
  170.    *
  171.    * Convenience variant of {@link #AnnotationQuery(String, List)}
  172.    * for cases where all predicates are of type
  173.    * {@link SemanticAnnotationHelper.ConstraintType#EQ}.
  174.    *
  175.    * @param annotationType the desired annotation type, for the annotations to
  176.    * be matched.
  177.    * @param featureConstraints the constraints over the features of the
  178.    * annotations to be found. This is represented as a {@link Map} from feature
  179.    * name (a {@link String}) to feature value (also a {@link String}).
  180.    *
  181.    * @see AnnotationQuery#AnnotationQuery(String, List)  
  182.    */
  183.   public AnnotationQuery(String annotationType,
  184.           Map<String, String> featureConstraints) {
  185.     if(featureConstraints == null){
  186.       featureConstraints = new HashMap<String, String>();
  187.     }
  188.     this.annotationType = annotationType;
  189.     this.constraints = new ArrayList<Constraint>(featureConstraints.size());
  190.     for(Map.Entry<String, String> entry : featureConstraints.entrySet()){
  191.       this.constraints.add(new Constraint(ConstraintType.EQ,
  192.               entry.getKey(), entry.getValue()));
  193.     }
  194.   }

  195.   /**
  196.    * Constructs a new Annotation Query.
  197.    *  
  198.    * @param annotationType the type of annotation being sought.
  199.    * @param constraints a list of constraints placed on the feature values. An
  200.    * empty constraints list will make no requests regarding the feature values,
  201.    * hence it will match all annotations of the right type.
  202.    */
  203.   public AnnotationQuery(String annotationType, List<Constraint> constraints) {
  204.     this.annotationType = annotationType;
  205.     this.constraints = constraints == null ? new ArrayList<Constraint>() :constraints;
  206.   }
  207.  
  208.   /* (non-Javadoc)
  209.    * @see gate.mimir.search.query.QueryNode#getQueryExecutor(java.util.Map)
  210.    */
  211.   public QueryExecutor getQueryExecutor(QueryEngine engine)
  212.           throws IOException {
  213.     return new AnnotationQueryExecutor(this, engine);
  214.   }
  215.  
  216.  
  217.   /**
  218.    * Gets the annotation type for this query.
  219.    * @return the annotationType
  220.    */
  221.   public String getAnnotationType() {
  222.     return annotationType;
  223.   }

  224.   /**
  225.    * Gets the feature constraints, represented as a {@link Map} from
  226.    * feature name (a {@link String}) to feature value (also a {@link String}).
  227.    * @return the featureConstraints
  228.    */
  229.   public List<Constraint> getConstraints() {
  230.     return constraints;
  231.   }


  232.   /**
  233.    * The annotation type for this query.
  234.    */
  235.   private String annotationType;
  236.  
  237.   /**
  238.    * The constrains over the annotation features.
  239.    */
  240.   private List<Constraint> constraints;
  241.  
  242.  
  243.   public String toString() {
  244.     return "Annotation ( type = " +
  245.     annotationType + ", features=" +
  246.     (constraints != null ? constraints.toString() : "[]") +
  247.     ")";
  248.   }

  249. }