blob: fcf28a616588b40dce41626d41732e5d4f7ed33f [file] [log] [blame]
Akron9bff63a2025-05-30 14:47:18 +02001package mapper
2
3import (
4 "testing"
5
Akron2ef703c2025-07-03 15:57:42 +02006 "github.com/KorAP/Koral-Mapper/config"
Akron9bff63a2025-05-30 14:47:18 +02007)
8
9// BenchmarkApplyQueryMappings benchmarks the optimized ApplyQueryMappings method
10func BenchmarkApplyQueryMappings(b *testing.B) {
11 // Setup test data
12 mappingList := config.MappingList{
13 ID: "test-mapper",
14 FoundryA: "opennlp",
15 LayerA: "p",
16 FoundryB: "tt",
17 LayerB: "p",
18 Mappings: []config.MappingRule{
19 "[PIAT] <> [PDAT]",
20 "[PPER & opennlp/m=PronType:Prs] <> [PPER]",
21 "[PRELS] <> [PRELAT]",
22 "[PIDAT] <> [PDAT]",
23 "[DET & opennlp/m=AdjType:Pdt] <> [ART]",
24 "[DET & opennlp/m=PronType:Ind] <> [PIS]",
25 },
26 }
27
28 mapper, err := NewMapper([]config.MappingList{mappingList})
29 if err != nil {
30 b.Fatalf("Failed to create mapper: %v", err)
31 }
32
33 // Test cases that represent different scenarios
34 testCases := []struct {
35 name string
36 data map[string]any
37 opts MappingOptions
38 }{
39 {
40 name: "Simple_term_match",
41 data: map[string]any{
42 "@type": "koral:term",
43 "foundry": "opennlp",
44 "key": "PIAT",
45 "layer": "p",
46 "match": "match:eq",
47 },
48 opts: MappingOptions{Direction: true},
49 },
50 {
51 name: "Complex_term_group_with_match",
52 data: map[string]any{
53 "@type": "koral:termGroup",
54 "operands": []any{
55 map[string]any{
56 "@type": "koral:term",
57 "foundry": "opennlp",
58 "key": "DET",
59 "layer": "p",
60 "match": "match:eq",
61 },
62 map[string]any{
63 "@type": "koral:term",
64 "foundry": "opennlp",
65 "key": "AdjType",
66 "layer": "m",
67 "match": "match:eq",
68 "value": "Pdt",
69 },
70 },
71 "relation": "relation:and",
72 },
73 opts: MappingOptions{Direction: true},
74 },
75 {
76 name: "No_match_scenario",
77 data: map[string]any{
78 "@type": "koral:term",
79 "foundry": "opennlp",
80 "key": "NOMATCH",
81 "layer": "p",
82 "match": "match:eq",
83 },
84 opts: MappingOptions{Direction: true},
85 },
86 {
87 name: "With_foundry_override",
88 data: map[string]any{
89 "@type": "koral:term",
90 "foundry": "opennlp",
91 "key": "PIAT",
92 "layer": "p",
93 "match": "match:eq",
94 },
95 opts: MappingOptions{
96 Direction: true,
97 FoundryB: "custom",
98 LayerB: "pos",
99 },
100 },
101 {
102 name: "Nested_token_structure",
103 data: map[string]any{
104 "@type": "koral:token",
105 "wrap": map[string]any{
106 "@type": "koral:termGroup",
107 "operands": []any{
108 map[string]any{
109 "@type": "koral:term",
110 "foundry": "opennlp",
111 "key": "PPER",
112 "layer": "p",
113 "match": "match:eq",
114 },
115 map[string]any{
116 "@type": "koral:term",
117 "foundry": "opennlp",
118 "key": "PronType",
119 "layer": "m",
120 "match": "match:eq",
121 "value": "Prs",
122 },
123 },
124 "relation": "relation:and",
125 },
126 },
127 opts: MappingOptions{Direction: true, AddRewrites: true},
128 },
129 }
130
131 // Run benchmarks for each test case
132 for _, tc := range testCases {
133 b.Run(tc.name, func(b *testing.B) {
134 for i := 0; i < b.N; i++ {
135 _, err := mapper.ApplyQueryMappings("test-mapper", tc.opts, tc.data)
136 if err != nil {
137 b.Fatalf("ApplyQueryMappings failed: %v", err)
138 }
139 }
140 })
141 }
142}
143
Akron9663af92026-02-20 13:45:08 +0100144// BenchmarkApplyResponseMappings benchmarks the SAX-based response annotation
145func BenchmarkApplyResponseMappings(b *testing.B) {
146 mappingList := config.MappingList{
147 ID: "bench-response",
148 FoundryA: "marmot",
149 LayerA: "p",
150 FoundryB: "opennlp",
151 LayerB: "p",
152 Mappings: []config.MappingRule{
153 "[DET] <> [DT]",
154 "[NN] <> [NOUN]",
155 "[ADJA] <> [ADJ]",
156 },
157 }
158
159 mapper, err := NewMapper([]config.MappingList{mappingList})
160 if err != nil {
161 b.Fatalf("Failed to create mapper: %v", err)
162 }
163
164 responseData := map[string]any{
165 "snippet": `<span title="marmot/p:DET">Der</span> <span title="marmot/p:ADJA">alte</span> <span title="marmot/p:NN">Mann</span>`,
166 }
167
168 opts := MappingOptions{Direction: AtoB}
169
170 b.ResetTimer()
171 for i := 0; i < b.N; i++ {
172 _, err := mapper.ApplyResponseMappings("bench-response", opts, responseData)
173 if err != nil {
174 b.Fatalf("ApplyResponseMappings failed: %v", err)
175 }
176 }
177}
178
Akron9bff63a2025-05-30 14:47:18 +0200179// BenchmarkApplyQueryMappingsWorstCase benchmarks the worst case scenario
180// where we have many rules but no matches (tests optimization effectiveness)
181func BenchmarkApplyQueryMappingsWorstCase(b *testing.B) {
182 // Create a mapper with many rules
183 manyRules := make([]config.MappingRule, 100)
184 for i := 0; i < 100; i++ {
185 ruleChar := string(rune('A' + i%26))
186 manyRules[i] = config.MappingRule("[UNUSED" + ruleChar + "] <> [TARGET" + ruleChar + "]")
187 }
188
189 mappingList := config.MappingList{
190 ID: "many-rules",
191 FoundryA: "opennlp",
192 LayerA: "p",
193 FoundryB: "tt",
194 LayerB: "p",
195 Mappings: manyRules,
196 }
197
198 mapper, err := NewMapper([]config.MappingList{mappingList})
199 if err != nil {
200 b.Fatalf("Failed to create mapper: %v", err)
201 }
202
203 // Test data that won't match any rule
204 testData := map[string]any{
205 "@type": "koral:term",
206 "foundry": "opennlp",
207 "key": "NOMATCH",
208 "layer": "p",
209 "match": "match:eq",
210 }
211
212 opts := MappingOptions{Direction: true}
213
214 b.ResetTimer()
215 for i := 0; i < b.N; i++ {
216 _, err := mapper.ApplyQueryMappings("many-rules", opts, testData)
217 if err != nil {
218 b.Fatalf("ApplyQueryMappings failed: %v", err)
219 }
220 }
221}