Add benchmark
diff --git a/mapper/benchmark_test.go b/mapper/benchmark_test.go
new file mode 100644
index 0000000..0e7cccb
--- /dev/null
+++ b/mapper/benchmark_test.go
@@ -0,0 +1,186 @@
+package mapper
+
+import (
+ "testing"
+
+ "github.com/KorAP/KoralPipe-TermMapper/config"
+)
+
+// BenchmarkApplyQueryMappings benchmarks the optimized ApplyQueryMappings method
+func BenchmarkApplyQueryMappings(b *testing.B) {
+ // Setup test data
+ mappingList := config.MappingList{
+ ID: "test-mapper",
+ FoundryA: "opennlp",
+ LayerA: "p",
+ FoundryB: "tt",
+ LayerB: "p",
+ Mappings: []config.MappingRule{
+ "[PIAT] <> [PDAT]",
+ "[PPER & opennlp/m=PronType:Prs] <> [PPER]",
+ "[PRELS] <> [PRELAT]",
+ "[PIDAT] <> [PDAT]",
+ "[DET & opennlp/m=AdjType:Pdt] <> [ART]",
+ "[DET & opennlp/m=PronType:Ind] <> [PIS]",
+ },
+ }
+
+ mapper, err := NewMapper([]config.MappingList{mappingList})
+ if err != nil {
+ b.Fatalf("Failed to create mapper: %v", err)
+ }
+
+ // Test cases that represent different scenarios
+ testCases := []struct {
+ name string
+ data map[string]any
+ opts MappingOptions
+ }{
+ {
+ name: "Simple_term_match",
+ data: map[string]any{
+ "@type": "koral:term",
+ "foundry": "opennlp",
+ "key": "PIAT",
+ "layer": "p",
+ "match": "match:eq",
+ },
+ opts: MappingOptions{Direction: true},
+ },
+ {
+ name: "Complex_term_group_with_match",
+ data: map[string]any{
+ "@type": "koral:termGroup",
+ "operands": []any{
+ map[string]any{
+ "@type": "koral:term",
+ "foundry": "opennlp",
+ "key": "DET",
+ "layer": "p",
+ "match": "match:eq",
+ },
+ map[string]any{
+ "@type": "koral:term",
+ "foundry": "opennlp",
+ "key": "AdjType",
+ "layer": "m",
+ "match": "match:eq",
+ "value": "Pdt",
+ },
+ },
+ "relation": "relation:and",
+ },
+ opts: MappingOptions{Direction: true},
+ },
+ {
+ name: "No_match_scenario",
+ data: map[string]any{
+ "@type": "koral:term",
+ "foundry": "opennlp",
+ "key": "NOMATCH",
+ "layer": "p",
+ "match": "match:eq",
+ },
+ opts: MappingOptions{Direction: true},
+ },
+ {
+ name: "With_foundry_override",
+ data: map[string]any{
+ "@type": "koral:term",
+ "foundry": "opennlp",
+ "key": "PIAT",
+ "layer": "p",
+ "match": "match:eq",
+ },
+ opts: MappingOptions{
+ Direction: true,
+ FoundryB: "custom",
+ LayerB: "pos",
+ },
+ },
+ {
+ name: "Nested_token_structure",
+ data: map[string]any{
+ "@type": "koral:token",
+ "wrap": map[string]any{
+ "@type": "koral:termGroup",
+ "operands": []any{
+ map[string]any{
+ "@type": "koral:term",
+ "foundry": "opennlp",
+ "key": "PPER",
+ "layer": "p",
+ "match": "match:eq",
+ },
+ map[string]any{
+ "@type": "koral:term",
+ "foundry": "opennlp",
+ "key": "PronType",
+ "layer": "m",
+ "match": "match:eq",
+ "value": "Prs",
+ },
+ },
+ "relation": "relation:and",
+ },
+ },
+ opts: MappingOptions{Direction: true, AddRewrites: true},
+ },
+ }
+
+ // Run benchmarks for each test case
+ for _, tc := range testCases {
+ b.Run(tc.name, func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ _, err := mapper.ApplyQueryMappings("test-mapper", tc.opts, tc.data)
+ if err != nil {
+ b.Fatalf("ApplyQueryMappings failed: %v", err)
+ }
+ }
+ })
+ }
+}
+
+// BenchmarkApplyQueryMappingsWorstCase benchmarks the worst case scenario
+// where we have many rules but no matches (tests optimization effectiveness)
+func BenchmarkApplyQueryMappingsWorstCase(b *testing.B) {
+ // Create a mapper with many rules
+ manyRules := make([]config.MappingRule, 100)
+ for i := 0; i < 100; i++ {
+ ruleChar := string(rune('A' + i%26))
+ manyRules[i] = config.MappingRule("[UNUSED" + ruleChar + "] <> [TARGET" + ruleChar + "]")
+ }
+
+ mappingList := config.MappingList{
+ ID: "many-rules",
+ FoundryA: "opennlp",
+ LayerA: "p",
+ FoundryB: "tt",
+ LayerB: "p",
+ Mappings: manyRules,
+ }
+
+ mapper, err := NewMapper([]config.MappingList{mappingList})
+ if err != nil {
+ b.Fatalf("Failed to create mapper: %v", err)
+ }
+
+ // Test data that won't match any rule
+ testData := map[string]any{
+ "@type": "koral:term",
+ "foundry": "opennlp",
+ "key": "NOMATCH",
+ "layer": "p",
+ "match": "match:eq",
+ }
+
+ opts := MappingOptions{Direction: true}
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ _, err := mapper.ApplyQueryMappings("many-rules", opts, testData)
+ if err != nil {
+ b.Fatalf("ApplyQueryMappings failed: %v", err)
+ }
+ }
+}