Github user mmiklavc commented on a diff in the pull request: https://github.com/apache/metron/pull/899#discussion_r161912600 --- Diff: metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/MathFunctions.java --- @@ -220,4 +219,156 @@ public Object apply(List<Object> args) { } } } + + @Stellar(namespace = "BOYERMOORE" + , name = "ADD" + , description = "Adds value to a Boyer-Moore list. [Boyer-Moore](https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_majority_vote_algorithm)" + , params = { + "state - state holder for list of values. If null, add will initialize a new state value.", + "value(s) - single object or list of values to add to the state object." + } + , returns = "Current state of the Boyer-Moore algorithm representing the current value that" + + "holds a plurality across all values added thus far." + ) + public static class BoyerMooreAdd extends BaseStellarFunction { + + @Override + public Object apply(List<Object> args) { + if (args.size() < 2) { + throw new IllegalArgumentException( + "Must pass an initial state (may be null) and at least one value to add to the list"); + } else { + BoyerMooreState state = ConversionUtils.convert(args.get(0), BoyerMooreState.class); + if (state == null) { + state = new BoyerMooreState(); + } + Object secondArg = args.get(1); + if (secondArg instanceof List) { + state.addAll((List) secondArg); + } else { + state.add(secondArg); + } + return state; + } + } + } + + public static class BoyerMooreState { + private Long counter; + private Object m; + + public BoyerMooreState() { + counter = 0L; + } + + public BoyerMooreState(Optional<List<BoyerMooreState>> previousStates, Optional<BoyerMooreState> currentState) { + this(); + currentState.ifPresent(boyerMooreState -> { + m = boyerMooreState.getPlurality(); + counter = boyerMooreState.getCounter(); + }); + for (BoyerMooreState state : previousStates.orElse(new ArrayList<>())) { + Object plurality = state.getPlurality(); + Long pluralityCount = state.getCounter(); + add(plurality, pluralityCount); + } + } + + public Object add(Object item) { + if (item != null) { + if (counter == 0) { + m = item; + counter = 1L; + } else if (item.equals(m)) { + counter++; + } else { + counter--; + } + } + return m; + } + + public Object add(Object item, Long counter) { + if (item != null) { + if (this.counter == 0) { + m = item; + this.counter = counter; --- End diff -- It's true, I make no effort to massage data types here - if you want to interpret a 1 as a string "1", then they will be considered distinct. I didn't have a suitable mechanism for determining types. I thought it was reasonable for a user to be able to make that type cast as part of their Stellar expression building, but I'm certainly open to suggestions.
---