private static List<List<FunctionSignature>> groupSignatures(List<FunctionSignature> functionSignatures) {
        List<List<FunctionSignature>> ret = new ArrayList<>();
        Set<Integer> skip = new HashSet<>();

        for (int i = 0; i < functionSignatures.size(); ++i) {
            if (skip.contains(i)) continue;

            FunctionSignature current = functionSignatures.get(i);
            if (current.getArgumentList().isEmpty()) {
                ret.add(List.of(current));
                continue;
            }
            if (!(current.getArgumentList().get(0) instanceof KeywordArgument)) {
                ret.add(List.of(current));
                continue;
            }

            List<FunctionSignature> group = new ArrayList<>() {{ add(current); }};

            for (int j = i + 1; j < functionSignatures.size(); ++j) {
                FunctionSignature candidate = functionSignatures.get(j);
                if (candidate.getArgumentList().size() != current.getArgumentList().size()) continue;
                if (!(candidate.getArgumentList().get(0) instanceof KeywordArgument)) continue;
                skip.add(j);
                group.add(candidate);
            }
            ret.add(group);
        }

        return ret;
    }
Some signatures are identical except differing in the first KeywordArgument,
for example closeness(field, name) and closeness(label, name).
This function makes groups based on that.
integration/schema-language-server/language-server/src/main/java/ai/vespa/schemals/lsp/schema/completion/provider/RankingExpressionCompletion.java