From 9915f4e134ef475d2f16f521ed214c5591f98295 Mon Sep 17 00:00:00 2001 From: Mike Barry Date: Sat, 12 Jun 2021 16:40:53 -0400 Subject: [PATCH] include matching key in expression --- .../flatmap/openmaptiles/MultiExpression.java | 29 +++++++++++++------ .../openmaptiles/MultiExpressionTest.java | 21 +++++++++++--- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/openmaptiles/src/main/java/com/onthegomap/flatmap/openmaptiles/MultiExpression.java b/openmaptiles/src/main/java/com/onthegomap/flatmap/openmaptiles/MultiExpression.java index 5a726b4b..05cff2a1 100644 --- a/openmaptiles/src/main/java/com/onthegomap/flatmap/openmaptiles/MultiExpression.java +++ b/openmaptiles/src/main/java/com/onthegomap/flatmap/openmaptiles/MultiExpression.java @@ -57,7 +57,7 @@ public record MultiExpression(Map expressions) { } } - private static boolean evaluate(Expression expr, Map input) { + private static boolean evaluate(Expression expr, Map input, List matchKeys) { // optimization: since this is evaluated for every input element, use // simple for loops instead of enhanced to avoid overhead of generating the // iterator (~30% speedup) @@ -69,24 +69,27 @@ public record MultiExpression(Map expressions) { } else { String str = value.toString(); if (match.exactMatches().contains(str)) { + matchKeys.add(match.field()); return true; } List wildcards = match.wildcards(); for (int i = 0; i < wildcards.size(); i++) { var target = wildcards.get(i); if (str.contains(target)) { + matchKeys.add(match.field()); return true; } } return false; } } else if (expr instanceof Expression.MatchField match) { + matchKeys.add(match.field()); return input.containsKey(match.field()); } else if (expr instanceof Expression.Or or) { List children = or.children(); for (int i = 0; i < children.size(); i++) { Expression child = children.get(i); - if (evaluate(child, input)) { + if (evaluate(child, input, matchKeys)) { return true; } } @@ -95,20 +98,22 @@ public record MultiExpression(Map expressions) { List children = and.children(); for (int i = 0; i < children.size(); i++) { Expression child = children.get(i); - if (!evaluate(child, input)) { + if (!evaluate(child, input, matchKeys)) { return false; } } return true; } else if (expr instanceof Expression.Not not) { - return !evaluate(not.child(), input); + return !evaluate(not.child(), input, new ArrayList<>()); } else { throw new IllegalArgumentException("Unrecognized expression: " + expr); } } - public List getMatches(Map input) { - List result = new ArrayList<>(); + public static record MatchWithTriggers(T match, List keys) {} + + public List> getMatchesWithTriggers(Map input) { + List> result = new ArrayList<>(); BitSet visited = new BitSet(ids.get()); if (input.size() < keyToExpressionsMap.size()) { for (String inputKey : input.keySet()) { @@ -129,7 +134,12 @@ public record MultiExpression(Map expressions) { return result; } - private void visitExpression(Map input, List result, BitSet visited, + public List getMatches(Map input) { + List> matches = getMatchesWithTriggers(input); + return matches.stream().map(d -> d.match).toList(); + } + + private void visitExpression(Map input, List> result, BitSet visited, List> expressionValues) { if (expressionValues != null) { // optimization: since this is evaluated for every element, generating an iterator @@ -138,8 +148,9 @@ public record MultiExpression(Map expressions) { var expressionValue = expressionValues.get(i); if (!visited.get(expressionValue.id)) { visited.set(expressionValue.id); - if (evaluate(expressionValue.exp(), input)) { - result.add(expressionValue.result); + List matchKeys = new ArrayList<>(); + if (evaluate(expressionValue.exp(), input, matchKeys)) { + result.add(new MatchWithTriggers<>(expressionValue.result, matchKeys)); } } } diff --git a/openmaptiles/src/test/java/com/onthegomap/flatmap/openmaptiles/MultiExpressionTest.java b/openmaptiles/src/test/java/com/onthegomap/flatmap/openmaptiles/MultiExpressionTest.java index 7be7cd38..7c4c84f3 100644 --- a/openmaptiles/src/test/java/com/onthegomap/flatmap/openmaptiles/MultiExpressionTest.java +++ b/openmaptiles/src/test/java/com/onthegomap/flatmap/openmaptiles/MultiExpressionTest.java @@ -3,6 +3,7 @@ package com.onthegomap.flatmap.openmaptiles; import static com.onthegomap.flatmap.openmaptiles.Expression.*; import static org.junit.jupiter.api.Assertions.assertEquals; +import java.util.Comparator; import java.util.List; import java.util.Map; import org.junit.jupiter.api.Test; @@ -158,11 +159,23 @@ public class MultiExpressionTest { matchAny("key3", "val3") ) )).index(); -// assertSameElements(List.of("a"), index.getMatches(Map.of("key1", "val1"))); - // TODO: match {key1=val1} => "key1" + assertSameElements(List.of(new MultiExpression.MultiExpressionIndex.MatchWithTriggers<>( + "a", List.of("key1") + )), index.getMatchesWithTriggers(Map.of("key1", "val1"))); + assertSameElements(List.of(new MultiExpression.MultiExpressionIndex.MatchWithTriggers<>( + "a", List.of("key2") + ), new MultiExpression.MultiExpressionIndex.MatchWithTriggers<>( + "b", List.of("key2") + )), index.getMatchesWithTriggers(Map.of("key2", "val2"))); + assertSameElements(List.of(new MultiExpression.MultiExpressionIndex.MatchWithTriggers<>( + "b", List.of("key3") + )), index.getMatchesWithTriggers(Map.of("key3", "val3"))); } - private static void assertSameElements(List a, List b) { - assertEquals(a.stream().sorted().toList(), b.stream().sorted().toList()); + private static void assertSameElements(List a, List b) { + assertEquals( + a.stream().sorted(Comparator.comparing(Object::toString)).toList(), + b.stream().sorted(Comparator.comparing(Object::toString)).toList() + ); } }