Repository: vespa-engine/vespa
File: container-search/src/main/java/com/yahoo/search/yql/YqlParser.java (Java)

Code before:
            // TODO: getIndex that is called once every term is rather expensive as it does sanity checking
            // that is not necessary. This is an issue when having many elements
            sameElement.addItem(convertExpression(term, field));
        }
        swapIndexCreator(prev);
        return sameElement;
    }

    /** Extract custom annotations for same element */
    private void extractSameElementAnnotations(OperatorNode<ExpressionOperator> ast, SameElementItem sameElement) {
        Object elementFilterObj = getAnnotation(ast, ELEMENT_FILTER, Object.class, null, "element filter list");
        if (elementFilterObj != null) {
            List<Integer> filter = new ArrayList<>();
            if (elementFilterObj instanceof List<?> list) {
                for (Object val : list) {
                    filter.add(convertToIntForElementFilter(val));
                }
            } else {
                filter.add(convertToIntForElementFilter(elementFilterObj));
            }
            sameElement.setElementFilter(filter);
        }
    }

    /** Element filter accepts Integer. Allows Long that is within Integer size. */
    private int convertToIntForElementFilter(Object val) {
        if (val instanceof Integer intVal) {
            return intVal;
        } else if (val instanceof Long longVal) {
            if (longVal > Integer.MAX_VALUE) {
                throw new IllegalArgumentException(
                        "elementFilter values must fit in int32 range, got: " + longVal);
            }
            return longVal.intValue();
        } else if (val instanceof Double || val instanceof Float) {
            throw new IllegalArgumentException(
                    "elementFilter values must be integers, not floating point numbers. Got: " + val);
        } else {
            throw new IllegalArgumentException(
                    "elementFilter values must be integers, got: " + val.getClass().getSimpleName());
        }
    }

    private void fillPhraseItem(CompositeItem phrase, String field, OperatorNode<ExpressionOperator> ast) {
        for (OperatorNode<ExpressionOperator> word : ast.<List<OperatorNode<ExpressionOperator>>> getArgument(1)) {
            if (word.getOperator() == ExpressionOperator.CALL) {
                List<String> names = word.getArgument(0);
                switch (names.get(0)) {
                    case PHRASE:
                        if (getAnnotation(word, ORIGIN, Map.class, null, ORIGIN_DESCRIPTION, false) == null) {
                            phrase.addItem(instantiatePhraseItem(field, word));

Review comment (suggestion):
consider catching negative/null values here as well, so the other function only need to do sort/dedup

Code after:
            // TODO: getIndex that is called once every term is rather expensive as it does sanity checking
            // that is not necessary. This is an issue when having many elements
            sameElement.addItem(convertExpression(term, field));
        }
        swapIndexCreator(prev);
        return sameElement;
    }

    /** Extract custom annotations for same element */
    private void extractSameElementAnnotations(OperatorNode<ExpressionOperator> ast, SameElementItem sameElement) {
        Object elementFilterObj = getAnnotation(ast, ELEMENT_FILTER, Object.class, null, "element filter list");
        if (elementFilterObj != null) {
            List<Integer> filter = new ArrayList<>();
            if (elementFilterObj instanceof List<?> list) {
                for (Object val : list) {
                    filter.add(convertToIntForElementFilter(val));
                }
            } else {
                filter.add(convertToIntForElementFilter(elementFilterObj));
            }
            sameElement.setElementFilter(filter);
        }
    }

    /** Element filter accepts Integer. Allows Long that is within Integer size. */
    private int convertToIntForElementFilter(Object val) {
        if (val == null) {
            throw new IllegalArgumentException("elementFilter cannot contain null values");
        }
        if (val instanceof Integer intVal) {
            if (intVal < 0) {
                throw new IllegalArgumentException("elementFilter values must be non-negative, got: " + val);
            }
            return intVal;
        } else if (val instanceof Long longVal) {
            if (longVal > Integer.MAX_VALUE) {
                throw new IllegalArgumentException(
                        "elementFilter values must fit in int32 range, got: " + longVal);
            }
            if (longVal < 0) {
                throw new IllegalArgumentException("elementFilter values must be non-negative, got: " + val);
            }
            return longVal.intValue();
        } else if (val instanceof Double || val instanceof Float) {
            throw new IllegalArgumentException(
                    "elementFilter values must be integers, not floating point numbers. Got: " + val);
        } else {
            throw new IllegalArgumentException(
                    "elementFilter values must be integers, got: " + val.getClass().getSimpleName());
        }
    }