public static Filter newFilter(
      QueryParseContext parseContext, String fieldPattern, String filterName) {
    final FieldMappers fieldNamesMappers =
        parseContext.mapperService().indexName(FieldNamesFieldMapper.NAME);
    final FieldNamesFieldMapper fieldNamesMapper =
        fieldNamesMappers == null ? null : (FieldNamesFieldMapper) fieldNamesMappers.mapper();

    MapperService.SmartNameObjectMapper smartNameObjectMapper =
        parseContext.smartObjectMapper(fieldPattern);
    if (smartNameObjectMapper != null && smartNameObjectMapper.hasMapper()) {
      // automatic make the object mapper pattern
      fieldPattern = fieldPattern + ".*";
    }

    List<String> fields = parseContext.simpleMatchToIndexNames(fieldPattern);
    if (fields.isEmpty()) {
      // no fields exists, so we should not match anything
      return Queries.MATCH_NO_FILTER;
    }
    MapperService.SmartNameFieldMappers nonNullFieldMappers = null;

    XBooleanFilter boolFilter = new XBooleanFilter();
    for (String field : fields) {
      MapperService.SmartNameFieldMappers smartNameFieldMappers =
          parseContext.smartFieldMappers(field);
      if (smartNameFieldMappers != null) {
        nonNullFieldMappers = smartNameFieldMappers;
      }
      Filter filter = null;
      if (fieldNamesMapper != null && fieldNamesMapper.enabled()) {
        final String f;
        if (smartNameFieldMappers != null && smartNameFieldMappers.hasMapper()) {
          f = smartNameFieldMappers.mapper().names().indexName();
        } else {
          f = field;
        }
        filter = fieldNamesMapper.termFilter(f, parseContext);
      }
      // if _field_names are not indexed, we need to go the slow way
      if (filter == null && smartNameFieldMappers != null && smartNameFieldMappers.hasMapper()) {
        filter = smartNameFieldMappers.mapper().rangeFilter(null, null, true, true, parseContext);
      }
      if (filter == null) {
        filter = new TermRangeFilter(field, null, null, true, true);
      }
      boolFilter.add(filter, BooleanClause.Occur.SHOULD);
    }

    // we always cache this one, really does not change... (exists)
    // its ok to cache under the fieldName cacheKey, since its per segment and the mapping applies
    // to this data on this segment...
    Filter filter =
        parseContext.cacheFilter(boolFilter, new CacheKeyFilter.Key("$exists$" + fieldPattern));

    filter = wrapSmartNameFilter(filter, nonNullFieldMappers, parseContext);
    if (filterName != null) {
      parseContext.addNamedFilter(filterName, filter);
    }
    return filter;
  }
  @Override
  public Filter parse(JsonQueryParseContext parseContext)
      throws IOException, QueryParsingException {
    JsonParser jp = parseContext.jp();

    JsonToken token = jp.nextToken();
    assert token == JsonToken.FIELD_NAME;
    String fieldName = jp.getCurrentName();

    jp.nextToken();
    String value = jp.getText();
    // move to the next token (from VALUE)
    jp.nextToken();

    if (value == null) {
      throw new QueryParsingException(index, "No value specified for term filter");
    }

    Filter filter = null;
    MapperService.SmartNameFieldMappers smartNameFieldMappers =
        parseContext.smartFieldMappers(fieldName);
    if (smartNameFieldMappers != null) {
      if (smartNameFieldMappers.hasMapper()) {
        filter = smartNameFieldMappers.mapper().fieldFilter(value);
      }
    }
    if (filter == null) {
      filter = new TermFilter(new Term(fieldName, value));
    }
    filter = parseContext.cacheFilterIfPossible(filter);
    return wrapSmartNameFilter(filter, smartNameFieldMappers, parseContext.indexCache());
  }
 public static Query wrapSmartNameQuery(
     Query query,
     @Nullable MapperService.SmartNameFieldMappers smartFieldMappers,
     QueryParseContext parseContext) {
   if (smartFieldMappers == null) {
     return query;
   }
   if (!smartFieldMappers.hasDocMapper()) {
     return query;
   }
   DocumentMapper docMapper = smartFieldMappers.docMapper();
   return new FilteredQuery(query, parseContext.cacheFilter(docMapper.typeFilter(), null));
 }
 private static GeoPointFieldMapper getGeoPointFieldMapper(
     String fieldName, MapperService mapperService) {
   MapperService.SmartNameFieldMappers smartMappers = mapperService.smartName(fieldName);
   if (smartMappers == null || !smartMappers.hasMapper()) {
     throw new IllegalArgumentException(String.format("column \"%s\" doesn't exist", fieldName));
   }
   FieldMapper mapper = smartMappers.mapper();
   if (!(mapper instanceof GeoPointFieldMapper)) {
     throw new IllegalArgumentException(
         String.format("column \"%s\" isn't of type geo_point", fieldName));
   }
   return (GeoPointFieldMapper) mapper;
 }
 public static Filter wrapSmartNameFilter(
     Filter filter,
     @Nullable MapperService.SmartNameFieldMappers smartFieldMappers,
     QueryParseContext parseContext) {
   if (smartFieldMappers == null) {
     return filter;
   }
   if (!smartFieldMappers.hasDocMapper()) {
     return filter;
   }
   DocumentMapper docMapper = smartFieldMappers.docMapper();
   return new AndFilter(
       ImmutableList.of(parseContext.cacheFilter(docMapper.typeFilter(), null), filter));
 }
  public ValueGeoDistanceFacetCollector(
      String facetName,
      String fieldName,
      double lat,
      double lon,
      DistanceUnit unit,
      GeoDistance geoDistance,
      GeoDistanceFacet.Entry[] entries,
      SearchContext context,
      String valueFieldName) {
    super(facetName, fieldName, lat, lon, unit, geoDistance, entries, context);

    MapperService.SmartNameFieldMappers smartMappers = context.smartFieldMappers(valueFieldName);
    if (smartMappers == null || !smartMappers.hasMapper()) {
      throw new FacetPhaseExecutionException(
          facetName, "No mapping found for field [" + valueFieldName + "]");
    }
    this.indexValueFieldName = smartMappers.mapper().names().indexName();
    this.valueFieldDataType = smartMappers.mapper().fieldDataType();
    this.aggregator = new Aggregator(fixedSourceDistance, entries);
  }
  public TermsLongOrdinalsFacetCollector(
      String facetName,
      String fieldName,
      int size,
      TermsFacet.ComparatorType comparatorType,
      boolean allTerms,
      SearchContext context,
      ImmutableSet<String> excluded) {
    super(facetName);
    this.fieldDataCache = context.fieldDataCache();
    this.size = size;
    this.comparatorType = comparatorType;
    this.numberOfShards = context.numberOfShards();

    MapperService.SmartNameFieldMappers smartMappers = context.mapperService().smartName(fieldName);
    if (smartMappers == null || !smartMappers.hasMapper()) {
      throw new ElasticSearchIllegalArgumentException(
          "Field ["
              + fieldName
              + "] doesn't have a type, can't run terms long facet collector on it");
    } else {
      // add type filter if there is exact doc mapper associated with it
      if (smartMappers.hasDocMapper()) {
        setFilter(context.filterCache().cache(smartMappers.docMapper().typeFilter()));
      }

      if (smartMappers.mapper().fieldDataType() != FieldDataType.DefaultTypes.LONG) {
        throw new ElasticSearchIllegalArgumentException(
            "Field ["
                + fieldName
                + "] is not of long type, can't run terms long facet collector on it");
      }

      this.indexFieldName = smartMappers.mapper().names().indexName();
      this.fieldDataType = smartMappers.mapper().fieldDataType();
    }

    if (excluded == null || excluded.isEmpty()) {
      this.excluded = null;
    } else {
      this.excluded = new TLongHashSet(excluded.size());
      for (String s : excluded) {
        this.excluded.add(Long.parseLong(s));
      }
    }

    // minCount is offset by -1
    if (allTerms) {
      minCount = -1;
    } else {
      minCount = 0;
    }

    this.aggregators = new ArrayList<ReaderAggregator>(context.searcher().subReaders().length);
  }
  @Override
  public Filter parse(QueryParseContext parseContext) throws IOException, QueryParsingException {
    XContentParser parser = parseContext.parser();

    String fieldName = null;
    String filterName = null;
    boolean nullValue = false;
    boolean existence = true;

    XContentParser.Token token;
    String currentFieldName = null;
    while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
      if (token == XContentParser.Token.FIELD_NAME) {
        currentFieldName = parser.currentName();
      } else if (token.isValue()) {
        if ("field".equals(currentFieldName)) {
          fieldName = parser.text();
        } else if ("null_value".equals(currentFieldName)) {
          nullValue = parser.booleanValue();
        } else if ("existence".equals(currentFieldName)) {
          existence = parser.booleanValue();
        } else if ("_name".equals(currentFieldName)) {
          filterName = parser.text();
        } else {
          throw new QueryParsingException(
              parseContext.index(), "[missing] filter does not support [" + currentFieldName + "]");
        }
      }
    }

    if (fieldName == null) {
      throw new QueryParsingException(
          parseContext.index(), "missing must be provided with a [field]");
    }

    if (!existence && !nullValue) {
      throw new QueryParsingException(
          parseContext.index(),
          "missing must have either existence, or null_value, or both set to true");
    }

    Filter existenceFilter = null;
    Filter nullFilter = null;

    MapperService.SmartNameFieldMappers smartNameFieldMappers =
        parseContext.smartFieldMappers(fieldName);

    if (existence) {
      if (smartNameFieldMappers != null && smartNameFieldMappers.hasMapper()) {
        existenceFilter =
            smartNameFieldMappers.mapper().rangeFilter(null, null, true, true, parseContext);
      }
      if (existenceFilter == null) {
        existenceFilter = new TermRangeFilter(fieldName, null, null, true, true);
      }

      // we always cache this one, really does not change... (exists)
      existenceFilter = parseContext.cacheFilter(existenceFilter, null);
      existenceFilter = new NotFilter(existenceFilter);
      // cache the not filter as well, so it will be faster
      existenceFilter = parseContext.cacheFilter(existenceFilter, null);
    }

    if (nullValue) {
      if (smartNameFieldMappers != null && smartNameFieldMappers.hasMapper()) {
        nullFilter = smartNameFieldMappers.mapper().nullValueFilter();
        if (nullFilter != null) {
          // cache the not filter as well, so it will be faster
          nullFilter = parseContext.cacheFilter(nullFilter, null);
        }
      }
    }

    Filter filter;
    if (nullFilter != null) {
      if (existenceFilter != null) {
        XBooleanFilter combined = new XBooleanFilter();
        combined.addShould(existenceFilter);
        combined.addShould(nullFilter);
        // cache the not filter as well, so it will be faster
        filter = parseContext.cacheFilter(combined, null);
      } else {
        filter = nullFilter;
      }
    } else {
      filter = existenceFilter;
    }

    if (filter == null) {
      return null;
    }

    filter = wrapSmartNameFilter(filter, smartNameFieldMappers, parseContext);
    if (filterName != null) {
      parseContext.addNamedFilter(filterName, existenceFilter);
    }
    return filter;
  }
  @Override
  public Query parse(QueryParseContext parseContext) throws IOException, QueryParsingException {
    XContentParser parser = parseContext.parser();

    XContentParser.Token token = parser.nextToken();
    if (token != XContentParser.Token.FIELD_NAME) {
      throw new QueryParsingException(
          parseContext.index(), "[range] query malformed, no field to indicate field name");
    }
    String fieldName = parser.currentName();
    token = parser.nextToken();
    if (token != XContentParser.Token.START_OBJECT) {
      throw new QueryParsingException(
          parseContext.index(), "[range] query malformed, after field missing start object");
    }

    BytesRef from = null;
    BytesRef to = null;
    boolean includeLower = true;
    boolean includeUpper = true;
    float boost = 1.0f;

    String currentFieldName = null;
    while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
      if (token == XContentParser.Token.FIELD_NAME) {
        currentFieldName = parser.currentName();
      } else {
        if ("from".equals(currentFieldName)) {
          from = parser.bytesOrNull();
        } else if ("to".equals(currentFieldName)) {
          to = parser.bytesOrNull();
        } else if ("include_lower".equals(currentFieldName)
            || "includeLower".equals(currentFieldName)) {
          includeLower = parser.booleanValue();
        } else if ("include_upper".equals(currentFieldName)
            || "includeUpper".equals(currentFieldName)) {
          includeUpper = parser.booleanValue();
        } else if ("boost".equals(currentFieldName)) {
          boost = parser.floatValue();
        } else if ("gt".equals(currentFieldName)) {
          from = parser.bytesOrNull();
          includeLower = false;
        } else if ("gte".equals(currentFieldName) || "ge".equals(currentFieldName)) {
          from = parser.bytesOrNull();
          includeLower = true;
        } else if ("lt".equals(currentFieldName)) {
          to = parser.bytesOrNull();
          includeUpper = false;
        } else if ("lte".equals(currentFieldName) || "le".equals(currentFieldName)) {
          to = parser.bytesOrNull();
          includeUpper = true;
        } else {
          throw new QueryParsingException(
              parseContext.index(), "[range] query does not support [" + currentFieldName + "]");
        }
      }
    }

    // move to the next end object, to close the field name
    token = parser.nextToken();
    if (token != XContentParser.Token.END_OBJECT) {
      throw new QueryParsingException(
          parseContext.index(), "[range] query malformed, does not end with an object");
    }

    Query query = null;
    MapperService.SmartNameFieldMappers smartNameFieldMappers =
        parseContext.smartFieldMappers(fieldName);
    if (smartNameFieldMappers != null) {
      if (smartNameFieldMappers.hasMapper()) {
        // LUCENE 4 UPGRADE Mapper#rangeQuery should use bytesref as well?
        query =
            smartNameFieldMappers
                .mapper()
                .rangeQuery(
                    from != null ? from.utf8ToString() : null,
                    to != null ? to.utf8ToString() : null,
                    includeLower,
                    includeUpper,
                    parseContext);
      }
    }
    if (query == null) {
      query = new TermRangeQuery(fieldName, from, to, includeLower, includeUpper);
    }
    query.setBoost(boost);
    return wrapSmartNameQuery(query, smartNameFieldMappers, parseContext);
  }
  public TermsShortFacetCollector(
      String facetName,
      String fieldName,
      int size,
      TermsFacet.ComparatorType comparatorType,
      boolean allTerms,
      SearchContext context,
      String scriptLang,
      String script,
      Map<String, Object> params) {
    super(facetName);
    this.fieldDataCache = context.fieldDataCache();
    this.size = size;
    this.comparatorType = comparatorType;
    this.numberOfShards = context.numberOfShards();

    MapperService.SmartNameFieldMappers smartMappers = context.mapperService().smartName(fieldName);
    if (smartMappers == null || !smartMappers.hasMapper()) {
      throw new ElasticSearchIllegalArgumentException(
          "Field ["
              + fieldName
              + "] doesn't have a type, can't run terms short facet collector on it");
    } else {
      // add type filter if there is exact doc mapper associated with it
      if (smartMappers.hasDocMapper()) {
        setFilter(context.filterCache().cache(smartMappers.docMapper().typeFilter()));
      }

      if (smartMappers.mapper().fieldDataType() != FieldDataType.DefaultTypes.SHORT) {
        throw new ElasticSearchIllegalArgumentException(
            "Field ["
                + fieldName
                + "] is not of short type, can't run terms short facet collector on it");
      }

      this.indexFieldName = smartMappers.mapper().names().indexName();
      this.fieldDataType = smartMappers.mapper().fieldDataType();
    }

    if (script != null) {
      this.script =
          new SearchScript(context.lookup(), scriptLang, script, params, context.scriptService());
    } else {
      this.script = null;
    }

    if (this.script == null) {
      aggregator = new StaticAggregatorValueProc(popFacets());
    } else {
      aggregator = new AggregatorValueProc(popFacets(), this.script);
    }

    if (allTerms) {
      try {
        for (IndexReader reader : context.searcher().subReaders()) {
          ShortFieldData fieldData =
              (ShortFieldData) fieldDataCache.cache(fieldDataType, reader, indexFieldName);
          fieldData.forEachValue(aggregator);
        }
      } catch (Exception e) {
        throw new FacetPhaseExecutionException(facetName, "failed to load all terms", e);
      }
    }
  }
  @Override
  public Filter parse(QueryParseContext parseContext) throws IOException, QueryParsingException {
    XContentParser parser = parseContext.parser();

    boolean cache = true;
    CacheKeyFilter.Key cacheKey = null;
    String fieldName = null;
    Object from = null;
    Object to = null;
    boolean includeLower = true;
    boolean includeUpper = true;

    String filterName = null;
    String currentFieldName = null;
    XContentParser.Token token;
    while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
      if (token == XContentParser.Token.FIELD_NAME) {
        currentFieldName = parser.currentName();
      } else if (token == XContentParser.Token.START_OBJECT) {
        fieldName = currentFieldName;
        while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
          if (token == XContentParser.Token.FIELD_NAME) {
            currentFieldName = parser.currentName();
          } else {
            if ("from".equals(currentFieldName)) {
              from = parser.objectBytes();
            } else if ("to".equals(currentFieldName)) {
              to = parser.objectBytes();
            } else if ("include_lower".equals(currentFieldName)
                || "includeLower".equals(currentFieldName)) {
              includeLower = parser.booleanValue();
            } else if ("include_upper".equals(currentFieldName)
                || "includeUpper".equals(currentFieldName)) {
              includeUpper = parser.booleanValue();
            } else if ("gt".equals(currentFieldName)) {
              from = parser.objectBytes();
              includeLower = false;
            } else if ("gte".equals(currentFieldName) || "ge".equals(currentFieldName)) {
              from = parser.objectBytes();
              includeLower = true;
            } else if ("lt".equals(currentFieldName)) {
              to = parser.objectBytes();
              includeUpper = false;
            } else if ("lte".equals(currentFieldName) || "le".equals(currentFieldName)) {
              to = parser.objectBytes();
              includeUpper = true;
            } else {
              throw new QueryParsingException(
                  parseContext.index(),
                  "[range] filter does not support [" + currentFieldName + "]");
            }
          }
        }
      } else if (token.isValue()) {
        if ("_name".equals(currentFieldName)) {
          filterName = parser.text();
        } else if ("_cache".equals(currentFieldName)) {
          cache = parser.booleanValue();
        } else if ("_cache_key".equals(currentFieldName) || "_cacheKey".equals(currentFieldName)) {
          cacheKey = new CacheKeyFilter.Key(parser.text());
        } else {
          throw new QueryParsingException(
              parseContext.index(), "[range] filter does not support [" + currentFieldName + "]");
        }
      }
    }

    if (fieldName == null) {
      throw new QueryParsingException(parseContext.index(), "No field specified for range filter");
    }

    Filter filter = null;
    MapperService.SmartNameFieldMappers smartNameFieldMappers =
        parseContext.smartFieldMappers(fieldName);
    if (smartNameFieldMappers != null) {
      if (smartNameFieldMappers.hasMapper()) {
        filter =
            smartNameFieldMappers
                .mapper()
                .rangeFilter(from, to, includeLower, includeUpper, parseContext);
      }
    }

    if (filter == null) {
      filter =
          new TermRangeFilter(
              fieldName,
              BytesRefs.toBytesRef(from),
              BytesRefs.toBytesRef(to),
              includeLower,
              includeUpper);
    }

    if (cache) {
      filter = parseContext.cacheFilter(filter, cacheKey);
    }

    filter = wrapSmartNameFilter(filter, smartNameFieldMappers, parseContext);
    if (filterName != null) {
      parseContext.addNamedFilter(filterName, filter);
    }
    return filter;
  }
  @Override
  public Filter parse(QueryParseContext parseContext) throws IOException, QueryParsingException {
    XContentParser parser = parseContext.parser();

    XContentParser.Token token;

    boolean cache = false;
    CacheKeyFilter.Key cacheKey = null;
    String filterName = null;
    String currentFieldName = null;
    double lat = 0;
    double lon = 0;
    String fieldName = null;
    Object vFrom = null;
    Object vTo = null;
    boolean includeLower = true;
    boolean includeUpper = true;
    DistanceUnit unit = DistanceUnit.KILOMETERS; // default unit
    GeoDistance geoDistance = GeoDistance.ARC;
    String optimizeBbox = "memory";
    boolean normalizeLon = true;
    boolean normalizeLat = true;
    while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
      if (token == XContentParser.Token.FIELD_NAME) {
        currentFieldName = parser.currentName();
      } else if (token == XContentParser.Token.START_ARRAY) {
        token = parser.nextToken();
        lon = parser.doubleValue();
        token = parser.nextToken();
        lat = parser.doubleValue();
        while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {}

        fieldName = currentFieldName;
      } else if (token == XContentParser.Token.START_OBJECT) {
        // the json in the format of -> field : { lat : 30, lon : 12 }
        String currentName = parser.currentName();
        fieldName = currentFieldName;
        while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
          if (token == XContentParser.Token.FIELD_NAME) {
            currentName = parser.currentName();
          } else if (token.isValue()) {
            if (currentName.equals(GeoPointFieldMapper.Names.LAT)) {
              lat = parser.doubleValue();
            } else if (currentName.equals(GeoPointFieldMapper.Names.LON)) {
              lon = parser.doubleValue();
            } else if (currentName.equals(GeoPointFieldMapper.Names.GEOHASH)) {
              double[] values = GeoHashUtils.decode(parser.text());
              lat = values[0];
              lon = values[1];
            }
          }
        }
      } else if (token.isValue()) {
        if (currentFieldName.equals("from")) {
          if (token == XContentParser.Token.VALUE_NULL) {
          } else if (token == XContentParser.Token.VALUE_STRING) {
            vFrom = parser.text(); // a String
          } else {
            vFrom = parser.numberValue(); // a Number
          }
        } else if (currentFieldName.equals("to")) {
          if (token == XContentParser.Token.VALUE_NULL) {
          } else if (token == XContentParser.Token.VALUE_STRING) {
            vTo = parser.text(); // a String
          } else {
            vTo = parser.numberValue(); // a Number
          }
        } else if ("include_lower".equals(currentFieldName)
            || "includeLower".equals(currentFieldName)) {
          includeLower = parser.booleanValue();
        } else if ("include_upper".equals(currentFieldName)
            || "includeUpper".equals(currentFieldName)) {
          includeUpper = parser.booleanValue();
        } else if ("gt".equals(currentFieldName)) {
          if (token == XContentParser.Token.VALUE_NULL) {
          } else if (token == XContentParser.Token.VALUE_STRING) {
            vFrom = parser.text(); // a String
          } else {
            vFrom = parser.numberValue(); // a Number
          }
          includeLower = false;
        } else if ("gte".equals(currentFieldName) || "ge".equals(currentFieldName)) {
          if (token == XContentParser.Token.VALUE_NULL) {
          } else if (token == XContentParser.Token.VALUE_STRING) {
            vFrom = parser.text(); // a String
          } else {
            vFrom = parser.numberValue(); // a Number
          }
          includeLower = true;
        } else if ("lt".equals(currentFieldName)) {
          if (token == XContentParser.Token.VALUE_NULL) {
          } else if (token == XContentParser.Token.VALUE_STRING) {
            vTo = parser.text(); // a String
          } else {
            vTo = parser.numberValue(); // a Number
          }
          includeUpper = false;
        } else if ("lte".equals(currentFieldName) || "le".equals(currentFieldName)) {
          if (token == XContentParser.Token.VALUE_NULL) {
          } else if (token == XContentParser.Token.VALUE_STRING) {
            vTo = parser.text(); // a String
          } else {
            vTo = parser.numberValue(); // a Number
          }
          includeUpper = true;
        } else if (currentFieldName.equals("unit")) {
          unit = DistanceUnit.fromString(parser.text());
        } else if (currentFieldName.equals("distance_type")
            || currentFieldName.equals("distanceType")) {
          geoDistance = GeoDistance.fromString(parser.text());
        } else if (currentFieldName.endsWith(GeoPointFieldMapper.Names.LAT_SUFFIX)) {
          lat = parser.doubleValue();
          fieldName =
              currentFieldName.substring(
                  0, currentFieldName.length() - GeoPointFieldMapper.Names.LAT_SUFFIX.length());
        } else if (currentFieldName.endsWith(GeoPointFieldMapper.Names.LON_SUFFIX)) {
          lon = parser.doubleValue();
          fieldName =
              currentFieldName.substring(
                  0, currentFieldName.length() - GeoPointFieldMapper.Names.LON_SUFFIX.length());
        } else if (currentFieldName.endsWith(GeoPointFieldMapper.Names.GEOHASH_SUFFIX)) {
          double[] values = GeoHashUtils.decode(parser.text());
          lat = values[0];
          lon = values[1];
          fieldName =
              currentFieldName.substring(
                  0, currentFieldName.length() - GeoPointFieldMapper.Names.GEOHASH_SUFFIX.length());
        } else if ("_name".equals(currentFieldName)) {
          filterName = parser.text();
        } else if ("_cache".equals(currentFieldName)) {
          cache = parser.booleanValue();
        } else if ("_cache_key".equals(currentFieldName) || "_cacheKey".equals(currentFieldName)) {
          cacheKey = new CacheKeyFilter.Key(parser.text());
        } else if ("optimize_bbox".equals(currentFieldName)
            || "optimizeBbox".equals(currentFieldName)) {
          optimizeBbox = parser.textOrNull();
        } else if ("normalize".equals(currentFieldName)) {
          normalizeLat = parser.booleanValue();
          normalizeLon = parser.booleanValue();
        } else {
          // assume the value is the actual value
          String value = parser.text();
          int comma = value.indexOf(',');
          if (comma != -1) {
            lat = Double.parseDouble(value.substring(0, comma).trim());
            lon = Double.parseDouble(value.substring(comma + 1).trim());
          } else {
            double[] values = GeoHashUtils.decode(value);
            lat = values[0];
            lon = values[1];
          }
          fieldName = currentFieldName;
        }
      }
    }

    Double from = null;
    Double to = null;
    if (vFrom != null) {
      if (vFrom instanceof Number) {
        from = unit.toMiles(((Number) vFrom).doubleValue());
      } else {
        from = DistanceUnit.parse((String) vFrom, unit, DistanceUnit.MILES);
      }
      from = geoDistance.normalize(from, DistanceUnit.MILES);
    }
    if (vTo != null) {
      if (vTo instanceof Number) {
        to = unit.toMiles(((Number) vTo).doubleValue());
      } else {
        to = DistanceUnit.parse((String) vTo, unit, DistanceUnit.MILES);
      }
      to = geoDistance.normalize(to, DistanceUnit.MILES);
    }

    if (normalizeLat) {
      lat = GeoUtils.normalizeLat(lat);
    }
    if (normalizeLon) {
      lon = GeoUtils.normalizeLon(lon);
    }

    MapperService.SmartNameFieldMappers smartMappers = parseContext.smartFieldMappers(fieldName);
    if (smartMappers == null || !smartMappers.hasMapper()) {
      throw new QueryParsingException(
          parseContext.index(), "failed to find geo_point field [" + fieldName + "]");
    }
    FieldMapper mapper = smartMappers.mapper();
    if (mapper.fieldDataType() != GeoPointFieldDataType.TYPE) {
      throw new QueryParsingException(
          parseContext.index(), "field [" + fieldName + "] is not a geo_point field");
    }
    GeoPointFieldMapper geoMapper = ((GeoPointFieldMapper.GeoStringFieldMapper) mapper).geoMapper();
    fieldName = mapper.names().indexName();

    Filter filter =
        new GeoDistanceRangeFilter(
            lat,
            lon,
            from,
            to,
            includeLower,
            includeUpper,
            geoDistance,
            fieldName,
            geoMapper,
            parseContext.indexCache().fieldData(),
            optimizeBbox);
    if (cache) {
      filter = parseContext.cacheFilter(filter, cacheKey);
    }
    filter = wrapSmartNameFilter(filter, smartMappers, parseContext);
    if (filterName != null) {
      parseContext.addNamedFilter(filterName, filter);
    }
    return filter;
  }
  @Override
  public Filter parse(QueryParseContext parseContext) throws IOException, QueryParsingException {
    XContentParser parser = parseContext.parser();

    String fieldName = null;
    ShapeRelation shapeRelation = ShapeRelation.INTERSECTS;
    String strategyName = null;
    ShapeBuilder shape = null;
    FilterCachingPolicy cache = parseContext.autoFilterCachePolicy();
    HashedBytesRef cacheKey = null;
    String filterName = null;

    String id = null;
    String type = null;
    String index = DEFAULTS.INDEX_NAME;
    String shapePath = DEFAULTS.SHAPE_FIELD_NAME;

    XContentParser.Token token;
    String currentFieldName = null;

    while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
      if (token == XContentParser.Token.FIELD_NAME) {
        currentFieldName = parser.currentName();
      } else if (token == XContentParser.Token.START_OBJECT) {
        fieldName = currentFieldName;

        while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
          if (token == XContentParser.Token.FIELD_NAME) {
            currentFieldName = parser.currentName();

            token = parser.nextToken();
            if ("shape".equals(currentFieldName)) {
              shape = ShapeBuilder.parse(parser);
            } else if ("relation".equals(currentFieldName)) {
              shapeRelation = ShapeRelation.getRelationByName(parser.text());
              if (shapeRelation == null) {
                throw new QueryParsingException(
                    parseContext.index(), "Unknown shape operation [" + parser.text() + "]");
              }
            } else if ("strategy".equals(currentFieldName)) {
              strategyName = parser.text();
            } else if ("indexed_shape".equals(currentFieldName)
                || "indexedShape".equals(currentFieldName)) {
              while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
                if (token == XContentParser.Token.FIELD_NAME) {
                  currentFieldName = parser.currentName();
                } else if (token.isValue()) {
                  if ("id".equals(currentFieldName)) {
                    id = parser.text();
                  } else if ("type".equals(currentFieldName)) {
                    type = parser.text();
                  } else if ("index".equals(currentFieldName)) {
                    index = parser.text();
                  } else if ("path".equals(currentFieldName)) {
                    shapePath = parser.text();
                  }
                }
              }
              if (id == null) {
                throw new QueryParsingException(
                    parseContext.index(), "ID for indexed shape not provided");
              } else if (type == null) {
                throw new QueryParsingException(
                    parseContext.index(), "Type for indexed shape not provided");
              }
              shape = fetchService.fetch(id, type, index, shapePath);
            } else {
              throw new QueryParsingException(
                  parseContext.index(),
                  "[geo_shape] filter does not support [" + currentFieldName + "]");
            }
          }
        }
      } else if (token.isValue()) {
        if ("_name".equals(currentFieldName)) {
          filterName = parser.text();
        } else if ("_cache".equals(currentFieldName)) {
          cache = parseContext.parseFilterCachePolicy();
        } else if ("_cache_key".equals(currentFieldName)) {
          cacheKey = new HashedBytesRef(parser.text());
        } else {
          throw new QueryParsingException(
              parseContext.index(),
              "[geo_shape] filter does not support [" + currentFieldName + "]");
        }
      }
    }

    if (shape == null) {
      throw new QueryParsingException(parseContext.index(), "No Shape defined");
    } else if (shapeRelation == null) {
      throw new QueryParsingException(parseContext.index(), "No Shape Relation defined");
    }

    MapperService.SmartNameFieldMappers smartNameFieldMappers =
        parseContext.smartFieldMappers(fieldName);
    if (smartNameFieldMappers == null || !smartNameFieldMappers.hasMapper()) {
      throw new QueryParsingException(
          parseContext.index(), "Failed to find geo_shape field [" + fieldName + "]");
    }

    FieldMapper fieldMapper = smartNameFieldMappers.mapper();
    // TODO: This isn't the nicest way to check this
    if (!(fieldMapper instanceof GeoShapeFieldMapper)) {
      throw new QueryParsingException(
          parseContext.index(), "Field [" + fieldName + "] is not a geo_shape");
    }

    GeoShapeFieldMapper shapeFieldMapper = (GeoShapeFieldMapper) fieldMapper;
    PrefixTreeStrategy strategy = shapeFieldMapper.defaultStrategy();
    if (strategyName != null) {
      strategy = shapeFieldMapper.resolveStrategy(strategyName);
    }

    Filter filter;
    if (strategy instanceof RecursivePrefixTreeStrategy
        && shapeRelation == ShapeRelation.DISJOINT) {
      // this strategy doesn't support disjoint anymore: but it did before, including creating
      // lucene fieldcache (!)
      // in this case, execute disjoint as exists && !intersects
      XBooleanFilter bool = new XBooleanFilter();
      Filter exists = ExistsFilterParser.newFilter(parseContext, fieldName, null);
      Filter intersects =
          strategy.makeFilter(GeoShapeQueryParser.getArgs(shape, ShapeRelation.INTERSECTS));
      bool.add(exists, BooleanClause.Occur.MUST);
      bool.add(intersects, BooleanClause.Occur.MUST_NOT);
      filter = bool;
    } else {
      filter = strategy.makeFilter(GeoShapeQueryParser.getArgs(shape, shapeRelation));
    }

    if (cache != null) {
      filter = parseContext.cacheFilter(filter, cacheKey, cache);
    }

    if (filterName != null) {
      parseContext.addNamedFilter(filterName, filter);
    }

    return filter;
  }
  @Override
  public Query parse(JsonQueryParseContext parseContext) throws IOException, QueryParsingException {
    JsonParser jp = parseContext.jp();

    JsonToken token = jp.nextToken();
    assert token == JsonToken.FIELD_NAME;
    String fieldName = jp.getCurrentName();

    String from = null;
    String to = null;
    boolean includeLower = true;
    boolean includeUpper = true;
    float boost = 1.0f;

    String currentFieldName = null;
    while ((token = jp.nextToken()) != JsonToken.END_OBJECT) {
      if (token == JsonToken.FIELD_NAME) {
        currentFieldName = jp.getCurrentName();
      } else {
        if ("from".equals(currentFieldName)) {
          if (jp.getCurrentToken() == JsonToken.VALUE_NULL) {
            from = null;
          } else {
            from = jp.getText();
          }
        } else if ("to".equals(currentFieldName)) {
          if (jp.getCurrentToken() == JsonToken.VALUE_NULL) {
            to = null;
          } else {
            to = jp.getText();
          }
        } else if ("include_lower".equals(currentFieldName)) {
          if (token == JsonToken.VALUE_NUMBER_INT) {
            includeLower = jp.getIntValue() != 0;
          } else if (token == JsonToken.VALUE_STRING) {
            includeLower = Booleans.parseBoolean(jp.getText(), includeLower);
          } else {
            includeLower = token == JsonToken.VALUE_TRUE;
          }
        } else if ("include_upper".equals(currentFieldName)) {
          if (token == JsonToken.VALUE_NUMBER_INT) {
            includeUpper = jp.getIntValue() != 0;
          } else if (token == JsonToken.VALUE_STRING) {
            includeUpper = Booleans.parseBoolean(jp.getText(), includeUpper);
          } else {
            includeUpper = token == JsonToken.VALUE_TRUE;
          }
        } else if ("boost".equals(currentFieldName)) {
          if (token == JsonToken.VALUE_STRING) {
            boost = Float.parseFloat(jp.getText());
          } else {
            boost = jp.getFloatValue();
          }
        } else if ("gt".equals(currentFieldName)) {
          if (jp.getCurrentToken() == JsonToken.VALUE_NULL) {
            from = null;
          } else {
            from = jp.getText();
          }
          includeLower = false;
        } else if ("gte".equals(currentFieldName)) {
          if (jp.getCurrentToken() == JsonToken.VALUE_NULL) {
            from = null;
          } else {
            from = jp.getText();
          }
          includeLower = true;
        } else if ("lt".equals(currentFieldName)) {
          if (jp.getCurrentToken() == JsonToken.VALUE_NULL) {
            to = null;
          } else {
            to = jp.getText();
          }
          includeUpper = false;
        } else if ("lte".equals(currentFieldName)) {
          if (jp.getCurrentToken() == JsonToken.VALUE_NULL) {
            to = null;
          } else {
            to = jp.getText();
          }
          includeUpper = true;
        }
      }
    }

    // move to the next end object, to close the field name
    token = jp.nextToken();
    assert token == JsonToken.END_OBJECT;

    Query query = null;
    MapperService.SmartNameFieldMappers smartNameFieldMappers =
        parseContext.smartFieldMappers(fieldName);
    if (smartNameFieldMappers != null) {
      if (smartNameFieldMappers.hasMapper()) {
        query = smartNameFieldMappers.mapper().rangeQuery(from, to, includeLower, includeUpper);
      }
    }
    if (query == null) {
      query = new TermRangeQuery(fieldName, from, to, includeLower, includeUpper);
    }
    query.setBoost(boost);
    return wrapSmartNameQuery(query, smartNameFieldMappers, parseContext.indexCache());
  }
  @Override
  public Query parse(QueryParseContext parseContext) throws IOException, QueryParsingException {
    XContentParser parser = parseContext.parser();

    String fieldName = null;
    boolean disableCoord = false;
    float boost = 1.0f;
    String minimumShouldMatch = null;
    List<String> values = newArrayList();

    String currentFieldName = null;
    XContentParser.Token token;
    while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
      if (token == XContentParser.Token.FIELD_NAME) {
        currentFieldName = parser.currentName();
      } else if (token == XContentParser.Token.START_ARRAY) {
        fieldName = currentFieldName;
        while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
          String value = parser.text();
          if (value == null) {
            throw new QueryParsingException(
                parseContext.index(), "No value specified for terms query");
          }
          values.add(value);
        }
      } else if (token.isValue()) {
        if ("disable_coord".equals(currentFieldName) || "disableCoord".equals(currentFieldName)) {
          disableCoord = parser.booleanValue();
        } else if ("minimum_match".equals(currentFieldName)
            || "minimumMatch".equals(currentFieldName)) {
          minimumShouldMatch = parser.textOrNull();
        } else if ("minimum_should_match".equals(currentFieldName)
            || "minimumShouldMatch".equals(currentFieldName)) {
          minimumShouldMatch = parser.textOrNull();
        } else if ("boost".equals(currentFieldName)) {
          boost = parser.floatValue();
        }
      } else {
        throw new QueryParsingException(
            parseContext.index(), "[terms] query does not support [" + currentFieldName + "]");
      }
    }

    FieldMapper mapper = null;
    MapperService.SmartNameFieldMappers smartNameFieldMappers =
        parseContext.smartFieldMappers(fieldName);
    String[] previousTypes = null;
    if (smartNameFieldMappers != null && smartNameFieldMappers.hasMapper()) {
      mapper = smartNameFieldMappers.mapper();
      if (smartNameFieldMappers.explicitTypeInNameWithDocMapper()) {
        previousTypes =
            QueryParseContext.setTypesWithPrevious(
                new String[] {smartNameFieldMappers.docMapper().type()});
      }
    }

    try {
      BooleanQuery query = new BooleanQuery(disableCoord);
      for (String value : values) {
        if (mapper != null) {
          query.add(
              new BooleanClause(mapper.termQuery(value, parseContext), BooleanClause.Occur.SHOULD));
        } else {
          query.add(new TermQuery(new Term(fieldName, value)), BooleanClause.Occur.SHOULD);
        }
      }
      query.setBoost(boost);
      Queries.applyMinimumShouldMatch(query, minimumShouldMatch);
      return wrapSmartNameQuery(
          optimizeQuery(fixNegativeQueryIfNeeded(query)), smartNameFieldMappers, parseContext);
    } finally {
      if (smartNameFieldMappers != null
          && smartNameFieldMappers.explicitTypeInNameWithDocMapper()) {
        QueryParseContext.setTypes(previousTypes);
      }
    }
  }