Skip to content

Commit 55eb9cf

Browse files
authored
Add search highlight formatter: plain. (#1683)
* Add search highlight formatter: plain. * Fix copyright year. * Revert copyright year on 2 formatters. * Use different highlight before/after tags.
1 parent dee0c77 commit 55eb9cf

File tree

2 files changed

+169
-0
lines changed

2 files changed

+169
-0
lines changed
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// Copyright (c) 2022 Couchbase, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package plain
16+
17+
import (
18+
"github.com/blevesearch/bleve/v2/registry"
19+
"github.com/blevesearch/bleve/v2/search/highlight"
20+
)
21+
22+
const Name = "plain"
23+
24+
const defaultPlainHighlightBefore = "<start>"
25+
const defaultPlainHighlightAfter = "<end>"
26+
27+
type FragmentFormatter struct {
28+
before string
29+
after string
30+
}
31+
32+
func NewFragmentFormatter(before, after string) *FragmentFormatter {
33+
return &FragmentFormatter{
34+
before: before,
35+
after: after,
36+
}
37+
}
38+
39+
func (a *FragmentFormatter) Format(f *highlight.Fragment, orderedTermLocations highlight.TermLocations) string {
40+
rv := ""
41+
curr := f.Start
42+
for _, termLocation := range orderedTermLocations {
43+
if termLocation == nil {
44+
continue
45+
}
46+
// make sure the array positions match
47+
if !termLocation.ArrayPositions.Equals(f.ArrayPositions) {
48+
continue
49+
}
50+
if termLocation.Start < curr {
51+
continue
52+
}
53+
if termLocation.End > f.End {
54+
break
55+
}
56+
// add the stuff before this location
57+
rv += string(f.Orig[curr:termLocation.Start])
58+
// start the highlight tag
59+
rv += a.before
60+
// add the term itself
61+
rv += string(f.Orig[termLocation.Start:termLocation.End])
62+
// end the highlight tag
63+
rv += a.after
64+
// update current
65+
curr = termLocation.End
66+
}
67+
// add any remaining text after the last token
68+
rv += string(f.Orig[curr:f.End])
69+
70+
return rv
71+
}
72+
73+
func Constructor(config map[string]interface{}, cache *registry.Cache) (highlight.FragmentFormatter, error) {
74+
before := defaultPlainHighlightBefore
75+
beforeVal, ok := config["before"].(string)
76+
if ok {
77+
before = beforeVal
78+
}
79+
after := defaultPlainHighlightAfter
80+
afterVal, ok := config["after"].(string)
81+
if ok {
82+
after = afterVal
83+
}
84+
return NewFragmentFormatter(before, after), nil
85+
}
86+
87+
func init() {
88+
registry.RegisterFragmentFormatter(Name, Constructor)
89+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Copyright (c) 2022 Couchbase, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package plain
16+
17+
import (
18+
"testing"
19+
20+
"github.com/blevesearch/bleve/v2/search"
21+
"github.com/blevesearch/bleve/v2/search/highlight"
22+
)
23+
24+
func TestPlainFragmentFormatter(t *testing.T) {
25+
tests := []struct {
26+
fragment *highlight.Fragment
27+
tlm search.TermLocationMap
28+
output string
29+
start string
30+
end string
31+
}{
32+
{
33+
fragment: &highlight.Fragment{
34+
Orig: []byte("the quick brown fox"),
35+
Start: 0,
36+
End: 19,
37+
},
38+
tlm: search.TermLocationMap{
39+
"quick": []*search.Location{
40+
{
41+
Pos: 2,
42+
Start: 4,
43+
End: 9,
44+
},
45+
},
46+
},
47+
output: "the <b>quick</b> brown fox",
48+
start: "<b>",
49+
end: "</b>",
50+
},
51+
{
52+
fragment: &highlight.Fragment{
53+
Orig: []byte("the quick brown fox"),
54+
Start: 0,
55+
End: 19,
56+
},
57+
tlm: search.TermLocationMap{
58+
"quick": []*search.Location{
59+
{
60+
Pos: 2,
61+
Start: 4,
62+
End: 9,
63+
},
64+
},
65+
},
66+
output: "the <em>quick</em> brown fox",
67+
start: "<em>",
68+
end: "</em>",
69+
},
70+
}
71+
72+
for _, test := range tests {
73+
plainFormatter := NewFragmentFormatter(test.start, test.end)
74+
otl := highlight.OrderTermLocations(test.tlm)
75+
result := plainFormatter.Format(test.fragment, otl)
76+
if result != test.output {
77+
t.Errorf("expected `%s`, got `%s`", test.output, result)
78+
}
79+
}
80+
}

0 commit comments

Comments
 (0)