0
0
Fork 0

cache values to avoid dynamic dispatch inside hot loop

This commit is contained in:
Marty Schoch 2016-08-25 16:24:26 -04:00
parent 60750c1614
commit 127f37212b
3 changed files with 44 additions and 16 deletions

View File

@ -571,10 +571,7 @@ func MultiSearch(ctx context.Context, req *SearchRequest, indexes ...Index) (*Se
// sort all hits with the requested order
if len(req.Sort) > 0 {
sorter := &multiSearchHitSorter{
hits: sr.Hits,
sort: req.Sort,
}
sorter := newMultiSearchHitSorter(req.Sort, sr.Hits)
sort.Sort(sorter)
}
@ -654,13 +651,24 @@ func (f *indexAliasImplFieldDict) Close() error {
}
type multiSearchHitSorter struct {
hits search.DocumentMatchCollection
sort search.SortOrder
hits search.DocumentMatchCollection
sort search.SortOrder
cachedScoring []bool
cachedDesc []bool
}
func newMultiSearchHitSorter(sort search.SortOrder, hits search.DocumentMatchCollection) *multiSearchHitSorter {
return &multiSearchHitSorter{
sort: sort,
hits: hits,
cachedScoring: sort.CacheIsScore(),
cachedDesc: sort.CacheDescending(),
}
}
func (m *multiSearchHitSorter) Len() int { return len(m.hits) }
func (m *multiSearchHitSorter) Swap(i, j int) { m.hits[i], m.hits[j] = m.hits[j], m.hits[i] }
func (m *multiSearchHitSorter) Less(i, j int) bool {
c := m.sort.Compare(m.hits[i], m.hits[j])
c := m.sort.Compare(m.cachedScoring, m.cachedDesc, m.hits[i], m.hits[j])
return c < 0
}

View File

@ -28,8 +28,10 @@ type HeapCollector struct {
results search.DocumentMatchCollection
facetsBuilder *search.FacetsBuilder
needDocIds bool
neededFields []string
needDocIds bool
neededFields []string
cachedScoring []bool
cachedDesc []bool
lowestMatchOutsideResults *search.DocumentMatch
}
@ -48,6 +50,8 @@ func NewHeapCollector(size int, skip int, sort search.SortOrder) *HeapCollector
hc.needDocIds = true
}
hc.neededFields = sort.RequiredFields()
hc.cachedScoring = sort.CacheIsScore()
hc.cachedDesc = sort.CacheDescending()
return hc
}
@ -148,7 +152,7 @@ func (hc *HeapCollector) collectSingle(ctx *search.SearchContext, reader index.I
// with this one comparision, we can avoid all heap operations if
// this hit would have been added and then immediately removed
if hc.lowestMatchOutsideResults != nil {
cmp := hc.sort.Compare(d, hc.lowestMatchOutsideResults)
cmp := hc.sort.Compare(hc.cachedScoring, hc.cachedDesc, d, hc.lowestMatchOutsideResults)
if cmp >= 0 {
// this hit can't possibly be in the result set, so avoid heap ops
ctx.DocumentMatchPool.Put(d)
@ -162,7 +166,7 @@ func (hc *HeapCollector) collectSingle(ctx *search.SearchContext, reader index.I
if hc.lowestMatchOutsideResults == nil {
hc.lowestMatchOutsideResults = removed
} else {
cmp := hc.sort.Compare(removed, hc.lowestMatchOutsideResults)
cmp := hc.sort.Compare(hc.cachedScoring, hc.cachedDesc, removed, hc.lowestMatchOutsideResults)
if cmp < 0 {
tmp := hc.lowestMatchOutsideResults
hc.lowestMatchOutsideResults = removed
@ -239,7 +243,7 @@ func (hc *HeapCollector) Len() int {
}
func (hc *HeapCollector) Less(i, j int) bool {
so := hc.sort.Compare(hc.results[i], hc.results[j])
so := hc.sort.Compare(hc.cachedScoring, hc.cachedDesc, hc.results[i], hc.results[j])
return -so < 0
}

View File

@ -168,11 +168,11 @@ func (so SortOrder) Value(doc *DocumentMatch) {
// Compare will compare two document matches using the specified sort order
// if both are numbers, we avoid converting back to term
func (so SortOrder) Compare(i, j *DocumentMatch) int {
func (so SortOrder) Compare(cachedScoring, cachedDesc []bool, i, j *DocumentMatch) int {
// compare the documents on all search sorts until a differences is found
for x, soi := range so {
for x := range so {
c := 0
if soi.RequiresScoring() {
if cachedScoring[x] {
if i.Score < j.Score {
c = -1
} else if i.Score > j.Score {
@ -187,7 +187,7 @@ func (so SortOrder) Compare(i, j *DocumentMatch) int {
if c == 0 {
continue
}
if soi.Descending() {
if cachedDesc[x] {
c = -c
}
return c
@ -229,6 +229,22 @@ func (so SortOrder) RequiredFields() []string {
return rv
}
func (so SortOrder) CacheIsScore() []bool {
var rv []bool
for _, soi := range so {
rv = append(rv, soi.RequiresScoring())
}
return rv
}
func (so SortOrder) CacheDescending() []bool {
var rv []bool
for _, soi := range so {
rv = append(rv, soi.Descending())
}
return rv
}
// SortFieldType lets you control some internal sort behavior
// normally leaving this to the zero-value of SortFieldAuto is fine
type SortFieldType int