intuit / fuzzy-matcher

A Java library to determine probability of objects being similar.
Apache License 2.0
226 stars 69 forks source link

Why Does Matching Fail in These Scenarios? #79

Open Hagar-Usama opened 2 months ago

Hagar-Usama commented 2 months ago

Hello,

I tried to modify some names for matching [Ahmed, Mohamed, Jouliana] by making slight alterations and then attempted to find matches. I anticipated matches like (1,2), (3,4), (3,5), (4,5), and (6,7).

Here's the code snippet I used:

String[][] input = {
    {"1", "Ahmed"},
    {"2", "Ahme"},
    {"3", "Mohamed"},
    {"4", "Mohame"},
    {"5", "Mahamad"},
    {"6", "Jouliana"},
    {"7", "Jouli"}
};

List<Document> documentList = Arrays.asList(input).stream().map(contact -> {
    return new Document.Builder(contact[0])
            .addElement(new Element.Builder<String>().setValue(contact[1]).setType(NAME).createElement())
            // .addElement(new Element.Builder<String>().setValue(contact[1]).setType(TEXT).createElement())
            .createDocument();
}).collect(Collectors.toList());

However, I only received the following result when the type is set to NAME:

Data: {[{'Mohamed'}]} Matched With: {[{'Mahamad'}]} Score: 1.0
Data: {[{'Mahamad'}]} Matched With: {[{'Mohamed'}]} Score: 1.0

And no results were obtained when the type is set to TEXT.

max-beatstars commented 2 weeks ago

Hi!

I'm having the same problem one the following example. No results are shown.

@Test
    void testFuzzy1() {
        String[][] input = {
            {"1", "Max D Alex"},
            {"2", "John Doe"},
            {"3", "Max D’Alex"}
        };

        List<Document> documentList = Arrays.asList(input).stream().map(contact -> {
            return new Document.Builder(contact[0])
                .addElement(new Element.Builder<String>().setValue(contact[1]).setType(NAME).createElement())
                .createDocument();
        }).collect(Collectors.toList());

        MatchService matchService = new MatchService();
        Map<String, List<Match<Document>>> result = matchService.applyMatchByDocId(documentList);

        result.entrySet().forEach(entry -> {
            entry.getValue().forEach(match -> {
                System.out.println("Data: " + match.getData() + " Matched With: " + match.getMatchedWith() + " Score: " + match.getScore().getResult());
            });
        });
    }
manishobhatia commented 2 weeks ago

Hi Hagar and Max

This library relies on Apache Soundex to give phonetically similar words. The example provided I believe might not have phonetic similarity for example Alex and D'Alex are not pronounced in the same manner.

In any case, there are other ways to override the default (Soundex) match algorithm used for Name matching, you could instead use N-Gram match. This relies on characters present in the words instead of phonetic matches.

You can do that by simply overriding the tokenization function of the Element and use triGramTokenizer() instead

hope this helps

max-beatstars commented 1 week ago

thanks a lot for your reply of this