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 regexpFilter( Object value, int flags, int maxDeterminizedStates, @Nullable QueryParseContext context) { if (fieldType.indexOptions() != IndexOptions.NONE || context == null) { return super.regexpFilter(value, flags, maxDeterminizedStates, context); } Collection<String> queryTypes = context.queryTypes(); if (queryTypes.size() == 1) { return new RegexpFilter( new Term( UidFieldMapper.NAME, Uid.createUidAsBytes( Iterables.getFirst(queryTypes, null), BytesRefs.toBytesRef(value))), flags, maxDeterminizedStates); } XBooleanFilter filter = new XBooleanFilter(); for (String queryType : queryTypes) { filter.add( new RegexpFilter( new Term( UidFieldMapper.NAME, Uid.createUidAsBytes(queryType, BytesRefs.toBytesRef(value))), flags, maxDeterminizedStates), BooleanClause.Occur.SHOULD); } return filter; }
/** * A filter for search. If a filter is required, will return it, otherwise, will return * <tt>null</tt>. */ public Filter searchFilter(String... types) { if (types == null || types.length == 0) { if (hasNested) { return NonNestedDocsFilter.INSTANCE; } else { return null; } } // if we filter by types, we don't need to filter by non nested docs // since they have different types (starting with __) if (types.length == 1) { DocumentMapper docMapper = documentMapper(types[0]); if (docMapper == null) { return new TermFilter(new Term(types[0])); } return docMapper.typeFilter(); } // see if we can use terms filter boolean useTermsFilter = true; for (String type : types) { DocumentMapper docMapper = documentMapper(type); if (docMapper == null) { useTermsFilter = false; break; } if (!docMapper.typeMapper().indexed()) { useTermsFilter = false; break; } } if (useTermsFilter) { Term[] typesTerms = new Term[types.length]; for (int i = 0; i < typesTerms.length; i++) { typesTerms[i] = TypeFieldMapper.TERM_FACTORY.createTerm(types[i]); } return new XTermsFilter(typesTerms); } else { XBooleanFilter bool = new XBooleanFilter(); for (String type : types) { DocumentMapper docMapper = documentMapper(type); if (docMapper == null) { bool.add( new FilterClause( new TermFilter(TypeFieldMapper.TERM_FACTORY.createTerm(type)), BooleanClause.Occur.SHOULD)); } else { bool.add(new FilterClause(docMapper.typeFilter(), BooleanClause.Occur.SHOULD)); } } return bool; } }
@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 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; }
/** * A filter for search. If a filter is required, will return it, otherwise, will return * <tt>null</tt>. */ @Nullable public Filter searchFilter(String... types) { boolean filterPercolateType = hasMapping(PercolatorService.TYPE_NAME); if (types != null && filterPercolateType) { for (String type : types) { if (PercolatorService.TYPE_NAME.equals(type)) { filterPercolateType = false; break; } } } Filter excludePercolatorType = null; if (filterPercolateType) { excludePercolatorType = new NotFilter(documentMapper(PercolatorService.TYPE_NAME).typeFilter()); } if (types == null || types.length == 0) { if (hasNested && filterPercolateType) { return new AndFilter(ImmutableList.of(excludePercolatorType, NonNestedDocsFilter.INSTANCE)); } else if (hasNested) { return NonNestedDocsFilter.INSTANCE; } else if (filterPercolateType) { return excludePercolatorType; } else { return null; } } // if we filter by types, we don't need to filter by non nested docs // since they have different types (starting with __) if (types.length == 1) { DocumentMapper docMapper = documentMapper(types[0]); if (docMapper == null) { return new TermFilter(new Term(types[0])); } return docMapper.typeFilter(); } // see if we can use terms filter boolean useTermsFilter = true; for (String type : types) { DocumentMapper docMapper = documentMapper(type); if (docMapper == null) { useTermsFilter = false; break; } if (!docMapper.typeMapper().fieldType().indexed()) { useTermsFilter = false; break; } } if (useTermsFilter) { BytesRef[] typesBytes = new BytesRef[types.length]; for (int i = 0; i < typesBytes.length; i++) { typesBytes[i] = new BytesRef(types[i]); } TermsFilter termsFilter = new TermsFilter(TypeFieldMapper.NAME, typesBytes); if (filterPercolateType) { return new AndFilter(ImmutableList.of(excludePercolatorType, termsFilter)); } else { return termsFilter; } } else { // Current bool filter requires that at least one should clause matches, even with a must // clause. XBooleanFilter bool = new XBooleanFilter(); for (String type : types) { DocumentMapper docMapper = documentMapper(type); if (docMapper == null) { bool.add( new FilterClause( new TermFilter(new Term(TypeFieldMapper.NAME, type)), BooleanClause.Occur.SHOULD)); } else { bool.add(new FilterClause(docMapper.typeFilter(), BooleanClause.Occur.SHOULD)); } } if (filterPercolateType) { bool.add(excludePercolatorType, BooleanClause.Occur.MUST); } return bool; } }
@Override public Query parse(QueryParseContext parseContext) throws IOException, QueryParsingException { XContentParser parser = parseContext.parser(); boolean queryFound = false; float boost = 1.0f; String parentType = null; boolean score = false; String queryName = null; String currentFieldName = null; XContentParser.Token token; XContentStructure.InnerQuery iq = 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) { // Usually, the query would be parsed here, but the child // type may not have been extracted yet, so use the // XContentStructure.<type> facade to parse if available, // or delay parsing if not. if ("query".equals(currentFieldName)) { iq = new XContentStructure.InnerQuery( parseContext, parentType == null ? null : new String[] {parentType}); queryFound = true; } else { throw new QueryParsingException( parseContext.index(), "[has_parent] query does not support [" + currentFieldName + "]"); } } else if (token.isValue()) { if ("type".equals(currentFieldName) || "parent_type".equals(currentFieldName) || "parentType".equals(currentFieldName)) { parentType = parser.text(); } else if ("_scope".equals(currentFieldName)) { throw new QueryParsingException( parseContext.index(), "the [_scope] support in [has_parent] query has been removed, use a filter as a facet_filter in the relevant global facet"); } else if ("score_type".equals(currentFieldName) || "scoreType".equals(currentFieldName)) { String scoreTypeValue = parser.text(); if ("score".equals(scoreTypeValue)) { score = true; } else if ("none".equals(scoreTypeValue)) { score = false; } } else if ("score_mode".equals(currentFieldName) || "scoreMode".equals(currentFieldName)) { String scoreModeValue = parser.text(); if ("score".equals(scoreModeValue)) { score = true; } else if ("none".equals(scoreModeValue)) { score = false; } } else if ("boost".equals(currentFieldName)) { boost = parser.floatValue(); } else if ("_name".equals(currentFieldName)) { queryName = parser.text(); } else { throw new QueryParsingException( parseContext.index(), "[has_parent] query does not support [" + currentFieldName + "]"); } } } if (!queryFound) { throw new QueryParsingException( parseContext.index(), "[has_parent] query requires 'query' field"); } if (parentType == null) { throw new QueryParsingException( parseContext.index(), "[has_parent] query requires 'parent_type' field"); } Query innerQuery = iq.asQuery(parentType); if (innerQuery == null) { return null; } DocumentMapper parentDocMapper = parseContext.mapperService().documentMapper(parentType); if (parentDocMapper == null) { throw new QueryParsingException( parseContext.index(), "[has_parent] query configured 'parent_type' [" + parentType + "] is not a valid type"); } innerQuery.setBoost(boost); // wrap the query with type query innerQuery = new XFilteredQuery( innerQuery, parseContext.cacheFilter(parentDocMapper.typeFilter(), null)); ParentChildIndexFieldData parentChildIndexFieldData = null; Set<String> parentTypes = new HashSet<>(5); parentTypes.add(parentType); for (DocumentMapper documentMapper : parseContext.mapperService()) { ParentFieldMapper parentFieldMapper = documentMapper.parentFieldMapper(); if (parentFieldMapper.active()) { parentChildIndexFieldData = parseContext.fieldData().getForField(parentFieldMapper); DocumentMapper parentTypeDocumentMapper = parseContext.mapperService().documentMapper(parentFieldMapper.type()); if (parentTypeDocumentMapper == null) { // Only add this, if this parentFieldMapper (also a parent) isn't a child of another // parent. parentTypes.add(parentFieldMapper.type()); } } } if (parentChildIndexFieldData == null) { throw new QueryParsingException( parseContext.index(), "[has_parent] no _parent field configured"); } Filter parentFilter; if (parentTypes.size() == 1) { DocumentMapper documentMapper = parseContext.mapperService().documentMapper(parentTypes.iterator().next()); parentFilter = parseContext.cacheFilter(documentMapper.typeFilter(), null); } else { XBooleanFilter parentsFilter = new XBooleanFilter(); for (String parentTypeStr : parentTypes) { DocumentMapper documentMapper = parseContext.mapperService().documentMapper(parentTypeStr); Filter filter = parseContext.cacheFilter(documentMapper.typeFilter(), null); parentsFilter.add(filter, BooleanClause.Occur.SHOULD); } parentFilter = parentsFilter; } Filter childrenFilter = parseContext.cacheFilter(new NotFilter(parentFilter), null); boolean deleteByQuery = "delete_by_query".equals(SearchContext.current().source()); Query query; if (!deleteByQuery && score) { query = new ParentQuery(parentChildIndexFieldData, innerQuery, parentType, childrenFilter); } else { query = new ParentConstantScoreQuery( parentChildIndexFieldData, innerQuery, parentType, childrenFilter); if (deleteByQuery) { query = new XConstantScoreQuery(new DeleteByQueryWrappingFilter(query)); } } query.setBoost(boost); if (queryName != null) { parseContext.addNamedFilter(queryName, new CustomQueryWrappingFilter(query)); } return query; }