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

This commit is contained in:
upstream-mirror
2026-09-15 22:27:16 +05:00
commit f8d3d9f0cf
797 changed files with 159570 additions and 0 deletions

122
geov2/evaluator.go Normal file
View 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))
}
}
}