@Override public SortField parse(XContentParser parser, SearchContext context) throws Exception { String script = null; String scriptLang = null; String type = null; Map<String, Object> params = null; boolean reverse = false; MultiValueMode sortMode = null; NestedInnerQueryParseSupport nestedHelper = null; XContentParser.Token token; String currentName = parser.currentName(); ScriptService.ScriptType scriptType = ScriptService.ScriptType.INLINE; while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { if (token == XContentParser.Token.FIELD_NAME) { currentName = parser.currentName(); } else if (token == XContentParser.Token.START_OBJECT) { if ("params".equals(currentName)) { params = parser.map(); } else if ("nested_filter".equals(currentName) || "nestedFilter".equals(currentName)) { if (nestedHelper == null) { nestedHelper = new NestedInnerQueryParseSupport(parser, context); } nestedHelper.filter(); } } else if (token.isValue()) { if ("reverse".equals(currentName)) { reverse = parser.booleanValue(); } else if ("order".equals(currentName)) { reverse = "desc".equals(parser.text()); } else if (ScriptService.SCRIPT_INLINE.match(currentName)) { script = parser.text(); scriptType = ScriptService.ScriptType.INLINE; } else if (ScriptService.SCRIPT_ID.match(currentName)) { script = parser.text(); scriptType = ScriptService.ScriptType.INDEXED; } else if (ScriptService.SCRIPT_FILE.match(currentName)) { script = parser.text(); scriptType = ScriptService.ScriptType.FILE; } else if (ScriptService.SCRIPT_LANG.match(currentName)) { scriptLang = parser.text(); } else if ("type".equals(currentName)) { type = parser.text(); } else if ("mode".equals(currentName)) { sortMode = MultiValueMode.fromString(parser.text()); } else if ("nested_path".equals(currentName) || "nestedPath".equals(currentName)) { if (nestedHelper == null) { nestedHelper = new NestedInnerQueryParseSupport(parser, context); } nestedHelper.setPath(parser.text()); } } } if (script == null) { throw new SearchParseException( context, "_script sorting requires setting the script to sort by"); } if (type == null) { throw new SearchParseException( context, "_script sorting requires setting the type of the script"); } final SearchScript searchScript = context .scriptService() .search( context.lookup(), scriptLang, script, scriptType, ScriptContext.Standard.SEARCH, params); if (STRING_SORT_TYPE.equals(type) && (sortMode == MultiValueMode.SUM || sortMode == MultiValueMode.AVG)) { throw new SearchParseException( context, "type [string] doesn't support mode [" + sortMode + "]"); } if (sortMode == null) { sortMode = reverse ? MultiValueMode.MAX : MultiValueMode.MIN; } // If nested_path is specified, then wrap the `fieldComparatorSource` in a // `NestedFieldComparatorSource` final Nested nested; if (nestedHelper != null && nestedHelper.getPath() != null) { FixedBitSetFilter rootDocumentsFilter = context.fixedBitSetFilterCache().getFixedBitSetFilter(NonNestedDocsFilter.INSTANCE); FixedBitSetFilter innerDocumentsFilter; if (nestedHelper.filterFound()) { innerDocumentsFilter = context.fixedBitSetFilterCache().getFixedBitSetFilter(nestedHelper.getInnerFilter()); } else { innerDocumentsFilter = context .fixedBitSetFilterCache() .getFixedBitSetFilter(nestedHelper.getNestedObjectMapper().nestedTypeFilter()); } nested = new Nested(rootDocumentsFilter, innerDocumentsFilter); } else { nested = null; } final IndexFieldData.XFieldComparatorSource fieldComparatorSource; switch (type) { case STRING_SORT_TYPE: fieldComparatorSource = new BytesRefFieldComparatorSource(null, null, sortMode, nested) { @Override protected SortedBinaryDocValues getValues(AtomicReaderContext context) { searchScript.setNextReader(context); final BinaryDocValues values = new BinaryDocValues() { final BytesRefBuilder spare = new BytesRefBuilder(); @Override public BytesRef get(int docID) { searchScript.setNextDocId(docID); spare.copyChars(searchScript.run().toString()); return spare.get(); } }; return FieldData.singleton(values, null); } @Override protected void setScorer(Scorer scorer) { searchScript.setScorer(scorer); } }; break; case NUMBER_SORT_TYPE: // TODO: should we rather sort missing values last? fieldComparatorSource = new DoubleValuesComparatorSource(null, Double.MAX_VALUE, sortMode, nested) { @Override protected SortedNumericDoubleValues getValues(AtomicReaderContext context) { searchScript.setNextReader(context); final NumericDoubleValues values = new NumericDoubleValues() { @Override public double get(int docID) { searchScript.setNextDocId(docID); return searchScript.runAsDouble(); } }; return FieldData.singleton(values, null); } @Override protected void setScorer(Scorer scorer) { searchScript.setScorer(scorer); } }; break; default: throw new SearchParseException( context, "custom script sort type [" + type + "] not supported"); } return new SortField("_script", fieldComparatorSource, reverse); }
@Override public FacetExecutor parse(String facetName, XContentParser parser, SearchContext context) throws IOException { String field = null; int size = 10; int shardSize = -1; String[] fieldsNames = null; ImmutableSet<BytesRef> excluded = ImmutableSet.of(); String regex = null; String regexFlags = null; TermsFacet.ComparatorType comparatorType = TermsFacet.ComparatorType.COUNT; String scriptLang = null; String script = null; ScriptService.ScriptType scriptType = null; Map<String, Object> params = null; boolean allTerms = false; String executionHint = 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) { if ("params".equals(currentFieldName)) { params = parser.map(); } else { throw new ElasticsearchParseException( "unknown parameter [" + currentFieldName + "] while parsing terms facet [" + facetName + "]"); } } else if (token == XContentParser.Token.START_ARRAY) { if ("exclude".equals(currentFieldName)) { ImmutableSet.Builder<BytesRef> builder = ImmutableSet.builder(); while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) { builder.add(parser.bytes()); } excluded = builder.build(); } else if ("fields".equals(currentFieldName)) { List<String> fields = Lists.newArrayListWithCapacity(4); while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) { fields.add(parser.text()); } fieldsNames = fields.toArray(new String[fields.size()]); } else { throw new ElasticsearchParseException( "unknown parameter [" + currentFieldName + "] while parsing terms facet [" + facetName + "]"); } } else if (token.isValue()) { if ("field".equals(currentFieldName)) { field = parser.text(); } else if (ScriptService.SCRIPT_INLINE.match(currentFieldName)) { script = parser.text(); scriptType = ScriptService.ScriptType.INLINE; } else if (ScriptService.SCRIPT_ID.match(currentFieldName)) { script = parser.text(); scriptType = ScriptService.ScriptType.INDEXED; } else if (ScriptService.SCRIPT_FILE.match(currentFieldName)) { script = parser.text(); scriptType = ScriptService.ScriptType.FILE; } else if (ScriptService.SCRIPT_LANG.match(currentFieldName)) { scriptLang = parser.text(); } else if ("size".equals(currentFieldName)) { size = parser.intValue(); } else if ("shard_size".equals(currentFieldName) || "shardSize".equals(currentFieldName)) { shardSize = parser.intValue(); } else if ("all_terms".equals(currentFieldName) || "allTerms".equals(currentFieldName)) { allTerms = parser.booleanValue(); } else if ("regex".equals(currentFieldName)) { regex = parser.text(); } else if ("regex_flags".equals(currentFieldName) || "regexFlags".equals(currentFieldName)) { regexFlags = parser.text(); } else if ("order".equals(currentFieldName) || "comparator".equals(currentFieldName)) { comparatorType = TermsFacet.ComparatorType.fromString(parser.text()); } else if ("execution_hint".equals(currentFieldName) || "executionHint".equals(currentFieldName)) { executionHint = parser.textOrNull(); } else { throw new ElasticsearchParseException( "unknown parameter [" + currentFieldName + "] while parsing terms facet [" + facetName + "]"); } } } if (fieldsNames != null && fieldsNames.length == 1) { field = fieldsNames[0]; fieldsNames = null; } Pattern pattern = null; if (regex != null) { pattern = Regex.compile(regex, regexFlags); } SearchScript searchScript = null; if (script != null) { searchScript = context.scriptService().search(context.lookup(), scriptLang, script, scriptType, params); } // shard_size cannot be smaller than size as we need to at least fetch <size> entries from every // shards in order to return <size> if (shardSize < size) { shardSize = size; } if (fieldsNames != null) { // in case of multi files, we only collect the fields that are mapped and facet on them. ArrayList<FieldMapper> mappers = new ArrayList<>(fieldsNames.length); for (int i = 0; i < fieldsNames.length; i++) { FieldMapper mapper = context.smartNameFieldMapper(fieldsNames[i]); if (mapper != null) { mappers.add(mapper); } } if (mappers.isEmpty()) { // non of the fields is mapped return new UnmappedFieldExecutor(size, comparatorType); } return new FieldsTermsStringFacetExecutor( mappers.toArray(new FieldMapper[mappers.size()]), size, shardSize, comparatorType, allTerms, context, excluded, pattern, searchScript); } if (field == null && script != null) { return new ScriptTermsStringFieldFacetExecutor( size, shardSize, comparatorType, context, excluded, pattern, scriptLang, script, scriptType, params, context.cacheRecycler()); } if (field == null) { throw new ElasticsearchParseException( "terms facet [" + facetName + "] must have a field, fields or script parameter"); } FieldMapper fieldMapper = context.smartNameFieldMapper(field); if (fieldMapper == null) { return new UnmappedFieldExecutor(size, comparatorType); } IndexFieldData indexFieldData = context.fieldData().getForField(fieldMapper); if (indexFieldData instanceof IndexNumericFieldData) { IndexNumericFieldData indexNumericFieldData = (IndexNumericFieldData) indexFieldData; if (indexNumericFieldData.getNumericType().isFloatingPoint()) { return new TermsDoubleFacetExecutor( indexNumericFieldData, size, shardSize, comparatorType, allTerms, context, excluded, searchScript, context.cacheRecycler()); } else { return new TermsLongFacetExecutor( indexNumericFieldData, size, shardSize, comparatorType, allTerms, context, excluded, searchScript, context.cacheRecycler()); } } else { if (script != null || "map".equals(executionHint)) { return new TermsStringFacetExecutor( indexFieldData, size, shardSize, comparatorType, allTerms, context, excluded, pattern, searchScript); } else if (indexFieldData instanceof IndexOrdinalsFieldData) { return new TermsStringOrdinalsFacetExecutor( (IndexOrdinalsFieldData) indexFieldData, size, shardSize, comparatorType, allTerms, context, excluded, pattern, ordinalsCacheAbove); } else { return new TermsStringFacetExecutor( indexFieldData, size, shardSize, comparatorType, allTerms, context, excluded, pattern, searchScript); } } }