I am trying to get a best match string matching to work using existing Java data structures. It is quite slow though, any suggestions to improve its performance will be welcomed .
the Sample data would look like this
Key | V
---------------------
0060175559138 | VIP
--------------
006017555 | National
--------------
006017 | Local
---------------
0060 | X
--------------
so a best match search on the key = 0060175552020 will return 006017555
One way I can think of is having multiple TreeMaps using hashing to divert the data into different maps hence making the search area smaller.
private final TreeMap<String, V> index;
public Set<V> syncBestMatch(String key) {
Entry<String,V> entry = index.headMap(key, true)
.descendingMap().entrySet().stream()
.filter(e -> isPartiallyOrFullyMatching(key, e.getKey()))
.findFirst()
.orElseThrow(() -> new NoMatchException("No match found"));
Set<V> results = new HashSet<>();
results.add(entry.getValue());
return results;
}
I prefer the TreeMap answer, but for completeness the same algorithm, now with binary search.
This algorithm is first logarithmic, and then does a loop. If there are no skipped entries, logarithmic time: fine. So the question is, how many entries need to be skipped.
If you store at every element a reference to its prefix: from
{ "00601755511", "International" },
to{ "006017555", "National" },
then you would only need to follow the prefix back links.Use a
TreeMap
and thefloorEntry(K key)
method:The following is simplified. Real code would need to search if an invalid entry is found, e.g. if the map had a key
0060175551000
, in which case you'd need to find the common prefix between the search key and the found key, then do the lookup again. Rinse and repeat.Output
UPDATE There is the full code, with loop for extended search.
Test
Output