Improve D&D registry normalization efficiency
This commit is contained in:
@@ -3,6 +3,7 @@ package locationregistry
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
@@ -228,24 +229,44 @@ func normalizeRecord(input dnd.Location, order shared.SourceRefOrder) (dnd.Locat
|
||||
|
||||
func exactDuplicateGroups(records []normalizedRecord) [][]int {
|
||||
groups := make([][]int, 0, len(records))
|
||||
groupPositions := make(map[string][]int, len(records))
|
||||
for index, record := range records {
|
||||
key := identity.ComparisonKey(record.location.Name)
|
||||
found := false
|
||||
for groupIndex, members := range groups {
|
||||
first := records[members[0]]
|
||||
if identity.ComparisonKey(first.location.Name) == key && reflect.DeepEqual(first.location.SourceRefs, record.location.SourceRefs) {
|
||||
key := exactDuplicateKey(record.location)
|
||||
comparisonName := identity.ComparisonKey(record.location.Name)
|
||||
matched := false
|
||||
for _, groupIndex := range groupPositions[key] {
|
||||
first := records[groups[groupIndex][0]]
|
||||
if identity.ComparisonKey(first.location.Name) == comparisonName && reflect.DeepEqual(first.location.SourceRefs, record.location.SourceRefs) {
|
||||
groups[groupIndex] = append(groups[groupIndex], index)
|
||||
found = true
|
||||
matched = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
groups = append(groups, []int{index})
|
||||
if matched {
|
||||
continue
|
||||
}
|
||||
groupPositions[key] = append(groupPositions[key], len(groups))
|
||||
groups = append(groups, []int{index})
|
||||
}
|
||||
return groups
|
||||
}
|
||||
|
||||
type duplicateKey struct {
|
||||
ComparisonName string `json:"comparison_name"`
|
||||
SourceRefs []source.SourceRef `json:"source_refs"`
|
||||
}
|
||||
|
||||
func exactDuplicateKey(location dnd.Location) string {
|
||||
encoded, err := json.Marshal(duplicateKey{
|
||||
ComparisonName: identity.ComparisonKey(location.Name),
|
||||
SourceRefs: location.SourceRefs,
|
||||
})
|
||||
if err != nil {
|
||||
panic("encode location duplicate key")
|
||||
}
|
||||
return string(encoded)
|
||||
}
|
||||
|
||||
func cloneLocation(input dnd.Location) dnd.Location {
|
||||
input.SourceRefs = cloneSourceRefs(input.SourceRefs)
|
||||
return input
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -60,6 +61,23 @@ func TestNormalizePreparesOnlyExactDuplicatesAndRetainsSameNameAndNestedPlaces(t
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkExactDuplicateGroupsManyDistinct(b *testing.B) {
|
||||
records := make([]normalizedRecord, 1_000)
|
||||
for index := range records {
|
||||
records[index] = normalizedRecord{location: dnd.Location{
|
||||
Name: "Location " + strconv.Itoa(index),
|
||||
SourceRefs: []source.SourceRef{{SourceID: "session", StartUnitID: index + 1, EndUnitID: index + 1}},
|
||||
}}
|
||||
}
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for iteration := 0; iteration < b.N; iteration++ {
|
||||
if groups := exactDuplicateGroups(records); len(groups) != len(records) {
|
||||
b.Fatalf("group count = %d, want %d", len(groups), len(records))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizeAppliesSafeAliasGroupAndUsesContextualInputs(t *testing.T) {
|
||||
client := &recordingLocationNormalizerClient{response: `{"duplicate_groups":[{"members":["candidate-000001","candidate-000002"],"canonical":"candidate-000002"}]}`}
|
||||
doc := semanticDocument()
|
||||
|
||||
Reference in New Issue
Block a user