Smile CDR ships with a rich set of built-in matching and similarity algorithms for MDM rule evaluation. For a complete reference of built-in algorithms, see the HAPI FHIR MDM Matching Rules documentation. For details on the core interfaces and the factory/registry pattern, see HAPI FHIR MDM Customizations.
When the built-in algorithms do not meet your requirements, you can implement custom matching and similarity algorithms and deploy them to Smile CDR via a customer JAR. Once registered, custom algorithms can be referenced by name in your MDM rules JSON alongside the built-in algorithms.
A custom matcher determines whether two FHIR field values match (boolean result). It consists of two parts: the matcher logic and a provider that names and supplies it.
Implement IMdmFieldMatcher from the hapi-fhir-server-mdm library:
import ca.uhn.fhir.mdm.rules.json.MdmMatcherJson;
import ca.uhn.fhir.mdm.rules.matcher.models.IMdmFieldMatcher;
import org.hl7.fhir.instance.model.api.IBase;
public class PhoneticMatcher implements IMdmFieldMatcher {
@Override
public boolean matches(IBase theLeftBase, IBase theRightBase, MdmMatcherJson theParams) {
String left = theLeftBase.toString();
String right = theRightBase.toString();
// Custom logic: check if the two values produce the same phonetic encoding
return PhoneticEncoder.encode(left).equals(PhoneticEncoder.encode(right));
}
}
Wrap the matcher in an IMdmFieldMatcherProvider that assigns it a unique name:
import ca.uhn.fhir.mdm.rules.matcher.models.IMdmFieldMatcher;
import ca.uhn.fhir.mdm.rules.matcher.models.IMdmFieldMatcherProvider;
public class PhoneticMatcherProvider implements IMdmFieldMatcherProvider {
@Override
public String getName() {
return "PHONETIC";
}
@Override
public IMdmFieldMatcher getMatcher() {
return new PhoneticMatcher();
}
}
The name returned by getName() is the string you will use in your MDM rules JSON to reference this algorithm.
A custom similarity measures how similar two FHIR field values are, returning a double between 0.0 (completely different) and 1.0 (identical).
Implement IMdmFieldSimilarity from the hapi-fhir-server-mdm library:
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.mdm.rules.similarity.IMdmFieldSimilarity;
import org.hl7.fhir.instance.model.api.IBase;
public class WeightedLevenshteinSimilarity implements IMdmFieldSimilarity {
@Override
public double similarity(
FhirContext theFhirContext, IBase theLeftBase, IBase theRightBase, boolean theExact) {
String left = theLeftBase.toString();
String right = theRightBase.toString();
if (theExact) {
return left.equals(right) ? 1.0 : 0.0;
}
// Custom weighted Levenshtein distance calculation
return calculateWeightedSimilarity(left, right);
}
private double calculateWeightedSimilarity(String theLeft, String theRight) {
// Custom implementation
return 0.0;
}
}
Wrap the similarity in an IMdmFieldSimilarityProvider:
import ca.uhn.fhir.mdm.rules.similarity.IMdmFieldSimilarity;
import ca.uhn.fhir.mdm.rules.similarity.IMdmFieldSimilarityProvider;
public class WeightedLevenshteinSimilarityProvider implements IMdmFieldSimilarityProvider {
@Override
public String getName() {
return "WEIGHTED_LEVENSHTEIN";
}
@Override
public IMdmFieldSimilarity getSimilarity() {
return new WeightedLevenshteinSimilarity();
}
}
Custom algorithm providers are deployed using the same customerlib mechanism used for custom interceptors.
Package your provider and algorithm classes into a JAR file containing only your classes (do not include library dependencies such as Spring or HAPI FHIR).
Place the JAR file in the smilecdr/customerlib directory.
Configure the custom_matcher_bean_types property on the MDM module with the fully-qualified class names of your provider classes. Multiple providers are separated by commas:
module.mdm.config.custom_matcher_bean_types=com.example.mdm.PhoneticMatcherProvider,com.example.mdm.WeightedLevenshteinSimilarityProvider
IMdmFieldMatcherProvider and IMdmFieldSimilarityProvider if it supplies both a matcher and a similarity algorithm.
Once deployed, reference your custom algorithm by name in the matchFields section of your MDM rules JSON, exactly as you would a built-in algorithm:
{
"name": "phoneticGiven",
"resourceType": "Patient",
"resourcePath": "name.given",
"matcher": {
"algorithm": "PHONETIC"
}
}
For a similarity-based field:
{
"name": "weightedFamilyName",
"resourceType": "Patient",
"resourcePath": "name.family",
"similarity": {
"algorithm": "WEIGHTED_LEVENSHTEIN",
"matchThreshold": 0.8
}
}
Algorithm names are case-sensitive and must exactly match the string returned by the provider's getName() method.
You can test custom algorithms interactively using the $mdm-evaluate operation. This operation accepts custom algorithm names in the algorithm parameter, allowing you to verify behavior before using them in your MDM rules.
Example request using a custom matcher:
{
"resourceType": "Parameters",
"parameter": [
{
"name": "compareTo",
"valueString": "Smith"
},
{
"name": "compareWith",
"valueString": "Smyth"
},
{
"name": "algorithmType",
"valueString": "matcher"
},
{
"name": "algorithm",
"valueString": "PHONETIC"
}
]
}
| Symptom | Cause | Resolution |
|---|---|---|
ClassNotFoundException at startup | JAR not in customerlib/ or wrong fully-qualified class name | Verify the JAR is in smilecdr/customerlib/ and the class name in custom_matcher_bean_types is correct |
| Duplicate algorithm name error | Custom algorithm name conflicts with a built-in or another custom algorithm | Change the getName() return value to a unique string |
| Algorithm not found in MDM rules | Name in JSON does not match provider getName() | Verify case-sensitive match between the JSON algorithm value and getName() |
Algorithm not found in $mdm-evaluate | Provider not registered | Verify custom_matcher_bean_types includes the provider class and check startup logs |
On startup, successfully registered custom algorithms are logged:
Registering custom MDM matcher: PHONETIC
Registering custom MDM similarity: WEIGHTED_LEVENSHTEIN
Check the MDM Troubleshooting Log for these messages if algorithms are not being recognized.
You are about to leave the Smile Digital Health documentation and navigate to the Open Source HAPI-FHIR Documentation.