snapshot of https://github.com/blevesearch/bleve.git (master, 2026-09-15; blobs > 131072B omitted)
Some checks failed
Coverage / coverage (push) Failing after 6s
Tests / test (1.24.x, ubuntu-latest) (push) Failing after 42s
Tests / test (1.26.x, ubuntu-latest) (push) Failing after 38s
Tests / test (1.25.x, ubuntu-latest) (push) Failing after 35s
Tests / test (1.25.x, windows-latest) (push) Has been cancelled
Tests / test (1.26.x, macos-latest) (push) Has been cancelled
Tests / test (1.26.x, windows-latest) (push) Has been cancelled
Tests / test (1.24.x, macos-latest) (push) Has been cancelled
Tests / test (1.24.x, windows-latest) (push) Has been cancelled
Tests / test (1.25.x, macos-latest) (push) Has been cancelled
Some checks failed
Coverage / coverage (push) Failing after 6s
Tests / test (1.24.x, ubuntu-latest) (push) Failing after 42s
Tests / test (1.26.x, ubuntu-latest) (push) Failing after 38s
Tests / test (1.25.x, ubuntu-latest) (push) Failing after 35s
Tests / test (1.25.x, windows-latest) (push) Has been cancelled
Tests / test (1.26.x, macos-latest) (push) Has been cancelled
Tests / test (1.26.x, windows-latest) (push) Has been cancelled
Tests / test (1.24.x, macos-latest) (push) Has been cancelled
Tests / test (1.24.x, windows-latest) (push) Has been cancelled
Tests / test (1.25.x, macos-latest) (push) Has been cancelled
This commit is contained in:
122
geov2/evaluator.go
Normal file
122
geov2/evaluator.go
Normal file
@@ -0,0 +1,122 @@
|
||||
// Copyright (c) 2026 Couchbase, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package geov2
|
||||
|
||||
import segment "github.com/blevesearch/scorch_segment_api/v2"
|
||||
|
||||
type queryEvaluator struct {
|
||||
queryInnerCells []uint64
|
||||
queryCrossCells []uint64
|
||||
|
||||
innerCells []uint64
|
||||
innerDocIDs []uint32
|
||||
|
||||
crossCells []uint64
|
||||
crossDocIDs []uint32
|
||||
}
|
||||
|
||||
func NewQueryEvaluator(query Query, geoData segment.GeoShapeV2Data) *queryEvaluator {
|
||||
return &queryEvaluator{
|
||||
queryInnerCells: query.InnerCells(),
|
||||
queryCrossCells: query.CrossCells(),
|
||||
innerCells: geoData.InnerCells(),
|
||||
innerDocIDs: geoData.InnerDocIDs(),
|
||||
crossCells: geoData.CrossCells(),
|
||||
crossDocIDs: geoData.CrossDocIDs(),
|
||||
}
|
||||
}
|
||||
|
||||
// find the leftmost index in arr where arr[i] >= target, or
|
||||
// len(arr) if no such index exists
|
||||
func binarySearchLeftmostGreaterOrEqual(arr []uint64, target uint64) int {
|
||||
lo, hi := 0, len(arr)
|
||||
for lo < hi {
|
||||
mid := int(uint(lo+hi) >> 1) // bitshift avoids the addition overflow risk
|
||||
if arr[mid] < target {
|
||||
lo = mid + 1
|
||||
} else {
|
||||
hi = mid
|
||||
}
|
||||
}
|
||||
return lo
|
||||
}
|
||||
|
||||
// forEachScoredDoc invokes fn exactly once for every docID present in either
|
||||
// score map, passing that doc's inner and cross scores (0 when the doc is
|
||||
// absent from the corresponding map).
|
||||
func forEachScoredDoc(innerScores, crossScores map[uint32]uint64,
|
||||
fn func(id uint32, inner, cross uint64)) {
|
||||
for id, inner := range innerScores {
|
||||
fn(id, inner, crossScores[id])
|
||||
}
|
||||
for id, cross := range crossScores {
|
||||
if _, ok := innerScores[id]; !ok {
|
||||
fn(id, 0, cross)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// scan and score the overlap of query inner cells with all index cells
|
||||
func (qe *queryEvaluator) rangeScanInner(innerScores, crossScores map[uint32]uint64) {
|
||||
for _, cell := range qe.queryInnerCells {
|
||||
minVal, maxVal := getCellSearchBounds(cell)
|
||||
cellLevel := getCellLevel(cell)
|
||||
rangeScanOne(cell, minVal, maxVal, cellLevel, qe.innerCells, qe.innerDocIDs, innerScores)
|
||||
rangeScanOne(cell, minVal, maxVal, cellLevel, qe.crossCells, qe.crossDocIDs, crossScores)
|
||||
}
|
||||
}
|
||||
|
||||
// scan and score the overlap of query cross cells with all index cells
|
||||
func (qe *queryEvaluator) rangeScanCross(innerScores, crossScores map[uint32]uint64) {
|
||||
for _, cell := range qe.queryCrossCells {
|
||||
minVal, maxVal := getCellSearchBounds(cell)
|
||||
cellLevel := getCellLevel(cell)
|
||||
rangeScanOne(cell, minVal, maxVal, cellLevel, qe.innerCells, qe.innerDocIDs, innerScores)
|
||||
rangeScanOne(cell, minVal, maxVal, cellLevel, qe.crossCells, qe.crossDocIDs, crossScores)
|
||||
}
|
||||
}
|
||||
|
||||
// scan and score the overlap of a single query cell with the given index cells
|
||||
func rangeScanOne(queryCell uint64, minVal, maxVal, cellLevel uint64,
|
||||
indexCells []uint64, docIds []uint32, scores map[uint32]uint64) {
|
||||
// find the range of index cells within the min/max bounds of the query cell
|
||||
// end will be < start if there are no index cells within the bounds
|
||||
start := binarySearchLeftmostGreaterOrEqual(indexCells, minVal)
|
||||
end := binarySearchLeftmostGreaterOrEqual(indexCells, maxVal+1) - 1
|
||||
|
||||
// score all index cells within the bounds of the query cell
|
||||
for i := start; i <= end; i++ {
|
||||
id := docIds[i]
|
||||
val := indexCells[i]
|
||||
|
||||
valLevel := getCellLevel(val)
|
||||
scores[id] += calcScore(cellLevel, valLevel)
|
||||
}
|
||||
|
||||
// score all parent cells of the query cell that are present in the index
|
||||
// since parent cells are not within the min/max bounds
|
||||
for level := int(cellLevel) - 1; level >= 0; level-- {
|
||||
// get the parent cell of the query cell at this level
|
||||
parentCell := getParentCell(queryCell, level)
|
||||
// search for the leftmost index of this parent cell in the index cells
|
||||
parentStart := binarySearchLeftmostGreaterOrEqual(indexCells, parentCell)
|
||||
|
||||
// score all index cells that match this parent cell exactly
|
||||
for i := parentStart; i < len(indexCells) && indexCells[i] == parentCell; i++ {
|
||||
id := docIds[i]
|
||||
scores[id] += calcScore(cellLevel, uint64(level))
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user