Esempio n. 1
0
        public IList <MPIMatchRecord> GetProbabilisticMatches(SearchVector searchVector)
        {
            //get subset of patients to match against
            var profileCandidates = GetCandidateBlock(searchVector);

            return(profileCandidates.Any()
                ? _matchEngine.FindMatches(searchVector, profileCandidates)
                : new List <MPIMatchRecord>());
        }
Esempio n. 2
0
        public List <MPIMatchRecord> FindMatches(SearchVector searchVector, IList <SearchVector> candidates)
        {
            if (_mpiTraceEnabled)
            {
                MPIMatchLogger.Verbose("Compared {0} candidates to {1}", candidates.Count, Describe(searchVector));
            }

            //setup parallelism
            var maxDegreeOfParallelism = 1;

            ThreadPool.SetMinThreads(maxDegreeOfParallelism, maxDegreeOfParallelism);
            var options = new ParallelOptions {
                MaxDegreeOfParallelism = maxDegreeOfParallelism
            };

            //compare search vector against each candidate vector and calculate match score for each candidate
            var allMatchRecords = candidates.AsParallel()
                                  .WithExecutionMode(ParallelExecutionMode.ForceParallelism)
                                  .WithDegreeOfParallelism(options.MaxDegreeOfParallelism)
                                  .Select(c => GetCandidateMatchRecord(searchVector, c))
                                  .ToList();

            allMatchRecords = SetConfidenceLevels(allMatchRecords);

            //consider only medium and high confidence matches
            var matchResults = allMatchRecords.Where(m => m.MatchConfidenceLevel != MPIConfidenceLevelLookup.Low).ToList();


            if (matchResults.Any())
            {
                if (!_mpiTraceEnabled)
                {
                    return(matchResults);
                }

                var highMatches = allMatchRecords.Where(r => r.MatchConfidenceLevel != MPIConfidenceLevelLookup.High).ToList();
                MPIMatchLogger.Information("{0} High confidence matches:", highMatches.Count);
                foreach (var hm in highMatches)
                {
                    MPIMatchLogger.Information("TotalScore: {0}, IdentifierScores: {1}", hm.TotalMatchScore, Describe(hm.MatchVector));
                }
                var mediumMatches = allMatchRecords.Where(r => r.MatchConfidenceLevel != MPIConfidenceLevelLookup.Medium).ToList();
                MPIMatchLogger.Information("{0} Medium confidence matches:", mediumMatches.Count);
                foreach (var mm in mediumMatches)
                {
                    MPIMatchLogger.Information("TotalScore: {0}, IdentifierScores: {1}", mm.TotalMatchScore, Describe(mm.MatchVector));
                }
                return(matchResults);
            }
            if (_mpiTraceEnabled)
            {
                MPINoMatchLogger.Verbose(Describe(searchVector), searchVector);
            }
            return(matchResults);
        }
Esempio n. 3
0
        private static MPIMatchRecord GetCandidateMatchRecord(SearchVector searchVector, SearchVector candidateVector)
        {
            //get list of identifier values for candidate

            //compare every element search vector to corresponding element in candidate vector
            var candidateMatchScores = searchVector.Identifiers.Select(sve =>
                                                                       GetIdentifierScore(sve, candidateVector.GetIdentifierByName(sve.IdentifierName)))
                                       .ToList();

            return(new MPIMatchRecord
            {
                //TODO: MatchedAcuperaId = candidate.AcuperaId,
                MatchType = "Probabilistic",
                MatchVector = candidateMatchScores,
            });
        }
Esempio n. 4
0
        public IList <SearchVector> GetCandidateBlock(SearchVector searchVector)
        {
            //TODO: use redis intersect functionality to combine blocking identifiers?
            //do we even want to intersect the blocking criteria?  may make more sense
            //to search through 1 block and if no match, search through another block.
            //intersecting the blocking criteria might be too restrictive
            //for now, assume blocking on lastname only

            var nameIdentifier = searchVector.GetBlockCandidate();
            var lastName       = nameIdentifier != null?nameIdentifier.Value.ToString() : string.Empty;

            //if lastname in search vector is shorter than key, use all characters
            var searchKey    = lastName.Length < _configuration.StringKeyLength ? lastName : lastName.Substring(0, _configuration.StringKeyLength);
            var candidateIds = _patientStore.LookupPatientsByPartialName(searchKey).ToList();

            return(_patientStore.GetMasterPatientIndexRecordsForListOfPatients(candidateIds).ToList());
        }
Esempio n. 5
0
 private static string Describe(SearchVector vector)
 {
     return(string.Empty);
     // TODO: return vector.Aggregate(string.Empty, (current, ve) => current + $"{ve.Identifier}, {ve.Value}, {ve.Score}");
 }