Home› Groups› Data Quality Score Feedback

Data Quality Score Feedback

Join

Two Flag Issues

Gordon Collett
Gordon Collett ✭✭✭✭✭
June 13 in Social Groups

I see two problems with the profile I am touching up right now: https://www.familysearch.org/en/tree/person/details/L7WV-4XN

The first is, I'll admit, a bit trivial:

Screenshot 2026-06-12 at 6.25.25 PM.png

Why is the flag substituting an incorrect character instead of showing the name in the profile? (Eldøy and Eldøen are the same name so I just dismissed this one but it can be seen in the dismissed Research Hints tab.)

More concerning is this:

Screenshot 2026-06-12 at 6.28.12 PM.png

This is something that needs to be checked out and the discrepancy identified. (It's actually an indexing error). Why did it not cause a flag?

Screenshot 2026-06-12 at 6.25.25 PM.png 145.6K
Screenshot 2026-06-12 at 6.28.12 PM.png 159.9K
2

Comments

  • Rhonda Budvarson
    Rhonda Budvarson ✭✭✭✭
    June 24

    @Gordon Collett here is the analysis. I am only posting this for you, because well, you will understand this. Please give suggestions for improving this. And/or definitely let us know your thoughts. Thank you :)

    Why "Kari Jensdatter Eldøy" vs "Hans Jensdtr Eldøen" Produces No NAME_MISMATCH

    For the trio: This is a case where the system is intentionally choosing not to surface a mismatch. The name comparison library is designed to be permissive — it prefers false negatives (missing a real mismatch) over false positives (flagging a mismatch that isn't real). The reasoning is that showing users a spurious "name mismatch" issue on a correctly attached source is more harmful to trust than quietly accepting a fuzzy match. The Kari/Hans case is an edge case where that permissiveness goes further than intended.

    Background

    The consistency calculator compares a person's conclusion names against source record names using NamesUtil from tree-name-comparison-lib. NamesUtil is a Spring @Component  with these defaults (configurable via @Value ):

    Property

    Default

    levenshtein.distance.threshold

    0.8

    levenshtein.insertion.cost

    1.0

    levenshtein.edit.cost

    1.0

    levenshtein.deletion.cost

    0.1

    The low deletion cost is the root cause.

    Step 1: Surname comparison passes

    The surnames (after name segmentation) are approximately "Jensdatter Eldøy" vs "Jensdtr Eldøen".

    compareNames first tries token-by-token (split on spaces). That fails — "eldøy" vs "eldøen" has a weighted distance of 2.0, and (5 - 2.0) / 5 = 0.60 < 0.8.

    Then it tries the no-spaces concatenation path — "jensdattereldøy" vs "jensdtreldøen":

    Weighted Levenshtein("jensdattereldøy", "jensdtreldøen"):
      - delete 'a'  → 0.1
      - delete 't'  → 0.1  (second 't' in "datter")
      - delete 'e'  → 0.1  (the 'e' in "datter")
      - y→e edit    → 1.0
      - insert 'n'  → 1.0
      Total ≈ 2.3
    
    Ratio = (len("jensdtreldøen") - 2.3) / len("jensdtreldøen")
          = (13 - 2.3) / 13 ≈ 0.823
    
    0.823 ≥ 0.80 → MATCH
    
    

    The ultra-low deletion cost (0.1) makes "Jensdatter" → "Jensdtr" essentially free: three deletions × 0.1 = 0.3. This single fact drives the whole result.

    Step 2: PatronymicUtil reinforces the match

    For female name comparisons (getFemaleNameComparisons), PatronymicUtil.getPatronymicVersionsOfSurnames is called to expand the acceptable surname pool. "dtr" is a recognized female patronymic abbreviation ending, so "Jensdtr" generates additional candidate forms (e.g. "Jensen", "Jens") that are also added to the comparison. Even without this, Step 1 already returns MATCH.

    Step 3: Given name mismatch gets buried by CROSS_MATCH

    With surnameComp = MATCH and givenComp = NOT_MATCH ("Kari" ≠ "Hans"), getFullNameMatchComparisonResult fires this condition:

    if (givenComp == NOT_MATCH || surnameComp == NOT_MATCH) → getFullNameCrossMatchComparisonResult
    
    

    What CROSS_MATCH is for

    CROSS_MATCH exists to handle a real problem with historical records: indexers sometimes put the surname in the given-name field or vice versa. For example:

    Given

    Surname

    Conclusion

    Kari

    Jensdatter

    Source record

    Jensdatter

    Kari

    A field-by-field comparison gives two NOT_MATCH results and would produce a spurious mismatch issue — but the names are clearly about the same person, just with transposed fields. CROSS_MATCH detects this by comparing each principal name part against the candidate's full name. If the parts are all present (just in different fields), it returns CROSS_MATCH and no issue is raised.

    This is an intentional design choice: prefer not surfacing an issue over surfacing a wrong one.

    What happens here

    Inside the cross-match path, the library checks whether "Kari" appears anywhere in "Hans Jensdtr Eldøen" and vice versa. It doesn't — this isn't a field-transposition case, it's a genuinely different given name. But the fallback when no cross-match is found still applies CROSS_MATCH to any unresolved part when the other part already matched:

    // givenComp is not a match type → replace with CROSS_MATCH
    // surnameComp is a match type  → keep as MATCH
    return new NameComparisonResult(CROSS_MATCH, MATCH, ...)
    
    

    And in ConsistencyCalculator.scoreNameComparison (line 369):

    case MATCH, CROSS_MATCH -> {
        // no issue
    }
    
    

    CROSS_MATCH is treated the same as MATCH — no issue is raised. The "Kari" vs "Hans" mismatch never surfaces. This is where the permissiveness goes further than intended: the fallback was designed for field-transposition cases, but it also swallows genuine given-name mismatches when the surname already matched.

    Summary

    Two separate permissive choices compound to suppress the mismatch:

    Factor

    Why it's permissive

    Effect

    Deletion cost = 0.1

    Cheap deletions prevent flagging abbreviations like "Jensdtr" vs "Jensdatter" as mismatches

    Surname fuzzy-matches via concatenation (ratio 0.823 ≥ 0.8)

    PatronymicUtil expansion

    Avoids flagging patronymic spelling variants as mismatches

    Reinforces the surname match by adding alternative forms

    CROSS_MATCH fallback

    Avoids flagging field-transposition as a mismatch

    Swallows the given-name mismatch ("Kari" vs "Hans") once the surname matched

    Each choice is reasonable on its own. Together they create a path where a source attached to the wrong person produces no issue.

    To make this flag, you would need to raise the threshold above 0.823, increase the deletion cost, or add explicit handling when the conclusion and source given names differ by gender.

    2
  • Gordon Collett
    Gordon Collett ✭✭✭✭✭
    June 25

    Wow! Thanks for the explanation. I always figured there was something more going on than a simple letter by letter comparison but this is even more complex than I had ever imagined.

    But it still seems that such a blatant problem with the first names being so different as to be raise the concern that an incorrect source is attached to the profile should not be ignored.

    I don't think differing genders for the first names should be added because it seems that this same situation would occur if the profile said Kari and the source said Guri or even Elizabeth. It seems that the first names having no possible connection (That is, treating Kari and Karin differently than Kari and Hansine) should be sufficient to raise that threshold enough to trigger the flag.

    2
  • Mary Anna Ebert
    Mary Anna Ebert ✭✭✭
    July 8

    @Gordon Collett Thanks!

    I will put it on the items to consider when we revisit some of the rules for the Quality Score.

    0
  • Gordon Collett
    Gordon Collett ✭✭✭✭✭
    July 9

    Did something get updated? On this profile, it is flagging differences in first names.

    Screenshot 2026-07-09 at 4.12.51 PM.png

    These names are all the same, just a few spelling variants so I'll just dismiss these eventually.

    Screenshot 2026-07-09 at 4.12.51 PM.png 288.1K
    1
  • Mary Anna Ebert
    Mary Anna Ebert ✭✭✭
    July 15

    @Gordon Collett Thanks for the message.

    We believe this is an unintended consequence of an update that was made, and are looking into it.

    Thanks again!

    1
Clear
No Groups Found

Categories

  • All Categories