-
Notifications
You must be signed in to change notification settings - Fork 0
/
fieldboost.go
203 lines (176 loc) · 4.92 KB
/
fieldboost.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
package sajari
import pb "code.sajari.com/protogen-go/sajari/engine/query/v1"
type fieldBoosts []FieldBoost
func (bs fieldBoosts) proto() ([]*pb.FieldBoost, error) {
pbs := make([]*pb.FieldBoost, 0, len(bs))
for _, b := range bs {
pb, err := b.proto()
if err != nil {
return nil, err
}
pbs = append(pbs, pb)
}
return pbs, nil
}
type featureFieldBoosts []FeatureFieldBoost
func (bs featureFieldBoosts) proto() ([]*pb.SearchRequest_FeatureQuery_FieldBoost, error) {
pbs := make([]*pb.SearchRequest_FeatureQuery_FieldBoost, 0, len(bs))
for _, b := range bs {
apb, err := b.proto()
if err != nil {
return nil, err
}
pbs = append(pbs, apb)
}
return pbs, nil
}
// FeatureFieldBoost is a wrapper which turns a FieldBoost into a feature. See
// NewFeatureFieldBoost.
type FeatureFieldBoost struct {
boost FieldBoost
value float64
}
func (ab FeatureFieldBoost) proto() (*pb.SearchRequest_FeatureQuery_FieldBoost, error) {
pbb, err := ab.boost.proto()
if err != nil {
return nil, err
}
return &pb.SearchRequest_FeatureQuery_FieldBoost{
FieldBoost: pbb,
Value: ab.value,
}, nil
}
// FeatureFieldBoost uses the normalised form of the FieldBoost b (computed internally) to count for
// a portion (value between 0 and 1) of the overall record score.
func NewFeatureFieldBoost(b FieldBoost, value float64) FeatureFieldBoost {
return FeatureFieldBoost{
boost: b,
value: value,
}
}
// FieldBoost is an interface satisfied by field-based boosting types.
//
// FieldBoosts are a way to influence the scoring of a record during a search based
// on the record's field data. All boosts are all normalised internally (converted to
// a number between 0 and 1).
type FieldBoost interface {
proto() (*pb.FieldBoost, error)
}
type filterFieldBoost struct {
filter Filter
value float64
}
func (fb filterFieldBoost) proto() (*pb.FieldBoost, error) {
pf, err := fb.filter.proto()
if err != nil {
return nil, err
}
return &pb.FieldBoost{
FieldBoost: &pb.FieldBoost_Filter_{
Filter: &pb.FieldBoost_Filter{
Filter: pf,
Value: fb.value,
},
},
}, nil
}
// FilterFieldBoost is a boost which is applied to records which satisfy the filter.
// Value must be greater than 0. Records which match the filter will receive a boost
// of Value
func FilterFieldBoost(f Filter, value float64) FieldBoost {
return &filterFieldBoost{
filter: f,
value: value,
}
}
// IntervalPoint is point-value pair used to construct an IntervalFieldBoost.
//
// It defines the boost value at a particular point in an interval.
type IntervalPoint struct {
// Point is a field value.
Point float64
// Value of boost to assign at this point.
Value float64
}
// IntervalFieldBoost represents an interval-based boost for numeric field values.
//
// An interval field boost is defined by a list of points with corresponding boost values.
// When a field value falls between between two IntervalPoints.Point values is computed linearly.
func IntervalFieldBoost(field string, values ...IntervalPoint) FieldBoost {
return intervalFieldBoost{
field: field,
values: values,
}
}
type intervalFieldBoost struct {
field string
values []IntervalPoint
}
type pointValues []IntervalPoint
func (pvs pointValues) proto() []*pb.FieldBoost_Interval_Point {
out := make([]*pb.FieldBoost_Interval_Point, 0, len(pvs))
for _, pv := range pvs {
out = append(out, &pb.FieldBoost_Interval_Point{
Point: pv.Point,
Value: pv.Value,
})
}
return out
}
func (db intervalFieldBoost) proto() (*pb.FieldBoost, error) {
return &pb.FieldBoost{
FieldBoost: &pb.FieldBoost_Interval_{
Interval: &pb.FieldBoost_Interval{
Field: db.field,
Points: pointValues(db.values).proto(),
},
},
}, nil
}
// ElementFieldBoost represents an element-based boosting for repeated field values.
//
// The resulting boost is the proportion of elements in elts that are also in the field
// value.
func ElementFieldBoost(field string, elts []string) FieldBoost {
return &elementFieldBoost{
field: field,
elts: elts,
}
}
type elementFieldBoost struct {
field string // Field containing stringArray.
elts []string // List of elements to match against.
}
func (eb elementFieldBoost) proto() (*pb.FieldBoost, error) {
return &pb.FieldBoost{
FieldBoost: &pb.FieldBoost_Element_{
Element: &pb.FieldBoost_Element{
Field: eb.field,
Elts: eb.elts,
},
},
}, nil
}
// TextFieldBoost represents a text-based boosting for string fields.
//
// It compares the text gainst the record field using a bag-of-words model.
func TextFieldBoost(field string, text string) FieldBoost {
return &textFieldBoost{
field: field,
text: text,
}
}
type textFieldBoost struct {
field string // Field containing string data.
text string // Text to compare against.
}
func (tb textFieldBoost) proto() (*pb.FieldBoost, error) {
return &pb.FieldBoost{
FieldBoost: &pb.FieldBoost_Text_{
Text: &pb.FieldBoost_Text{
Field: tb.field,
Text: tb.text,
},
},
}, nil
}