I am trying to create a fast search function to determine the prefix of a phone number.
I am loading prefix data from database into memory as TreeMap, where key is prefix and value is an object containing information about this prefix(country etc).
This is how TreeMap is populated:
private static TreeMap<String, PrefixData> prefixMap = new TreeMap<>();
//EXAMPLE of DB query
try {
Class.forName("org.postgresql.Driver");
Connection connection = DriverManager.getConnection(dbURL, dbUser, dbPass);
connection.setAutoCommit(false);
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM countries_prefixes");
//Looping resultset
while (rs.next()) {
//TODO Review fields that must be stored in memory
String country = rs.getString("name");
//Populating map with data object (keeping nr prefix as key and object as value)
prefixMap.put(rs.getString("country_prefix"), new PrefixData(country));
}
rs.close();
stmt.close();
connection.close();
} catch (ClassNotFoundException | SQLException e) {
System.out.println(e.toString());
}
Lets say I have phone numbers I want to check: 37251845632; 35844021546; 34651478966 etc ...
Some prefixes are 1 digit long, some 2 digits long, some 3 digits long and so on...
So I created a loop, that works:
//TODO Try some other search methods (Tries)
//array for prefix length priority
int[] sequence = {3, 4, 2, 1, 5, 6};
//Performing search from the map
for (int i = 0; i < sequence.length; i++) {
//Extracting prefix from phone nr
String prefix = phoneNr.substring(1, sequence[i] + 1);
if (prefixMap.containsKey(prefix)) {
PrefixData pdata = prefixMap.get(prefix);
System.out.println(String.format("Found matching key [%s] in TreeMap", prefix));
System.out.println(String.format("[NAME: %s] [REGEX: %s] ", pdata.getCountryName(), pdata.getNrRegex()));
//Validate number format with regex
if (pdata.getNrRegex().trim() != null && !pdata.getNrRegex().trim().isEmpty()) {
System.out.println("Regex for number validation is present!");
if (phoneNr.matches(pdata.getNrRegex().replaceAll("^/|/$", ""))) {
System.out.println("NUMBER IS VALID!");
} else {
System.out.println("INVALID NUMBER!");
}
}
return pdata;
}
}
return null;
}
Now the loop works well, but it is slow. I've heard something about Tries, which is faster, but I don't understand how to implement this in my scenario.
Any help is appreciated!
As I said, the loop works, but this is not a nice way to achieve my goal.
So I did a little bit of research and came up with solution that is using prefix tree (Trie) implementation.
Little reading what Trie is can be found here.
And now the Trie implementation part. I knew that it would be faster to find a code that is already written and tested, so I found Google implementation here. And Vladimir Kroz's implementation here.
Made some minor modifications and this is the solution. I will provide both solutions:
Prefixmap interface
PrefixTrie class
Vladimir Kroz implementation: Trie class
And finally the Testing part
Hope that this answer is somewhat helpful to others also! Cheers!