Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions lucene/CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,13 @@ API Changes

New Features
---------------------
* GITHUB#16357: Add shared-floor kNN collection to the sandbox module: GlobalKnnFloor,
FloorAwareKnnCollector and SharedFloorKnnCollectorManager let concurrent searchers of one query
(segments in one process, or shards across processes via GlobalKnnFloor#advertise) prune graph
exploration against a shared lower bound of the query's final merged top-k cutoff. This remains
an approximate-search optimization: deployments must measure its recall/visit trade-off. Opt-in,
no changes to core search. (Kristian Rickert)

* GITHUB#16241: Add HangulCompositionCharFilter to analysis-nori for opt-in composition of
modern Hangul conjoining jamo before KoreanTokenizer. (Mingi Jeong)

Expand Down
1 change: 1 addition & 0 deletions lucene/sandbox/src/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
exports org.apache.lucene.sandbox.document;
exports org.apache.lucene.sandbox.queries;
exports org.apache.lucene.sandbox.search;
exports org.apache.lucene.sandbox.search.knn;
exports org.apache.lucene.sandbox.index;
exports org.apache.lucene.sandbox.facet;
exports org.apache.lucene.sandbox.facet.recorders;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.lucene.sandbox.search.knn;

import java.util.concurrent.locks.ReentrantLock;

/**
* A blocking bounded min heap that stores floats. The top element is the lowest value of the heap.
*
* <p>A primitive priority queue that maintains a partial ordering of its elements such that the
* least element can always be found in constant time. Implementation is based on {@link
* org.apache.lucene.util.LongHeap}
*
* @lucene.internal
*/
final class BlockingFloatHeap {
private final int maxSize;
private final float[] heap;
private final ReentrantLock lock;
private int size;

public BlockingFloatHeap(int maxSize) {
if (maxSize < 1) {
throw new IllegalArgumentException("maxSize must be at least 1, got: " + maxSize);
}
this.maxSize = maxSize;
this.heap = new float[maxSize + 1];
this.lock = new ReentrantLock();
this.size = 0;
}

/**
* Inserts a value into this heap.
*
* <p>If the number of values would exceed the heap's maxSize, the least value is discarded
*
* @param value the value to add
* @return the new 'top' element in the queue.
*/
public float offer(float value) {
lock.lock();
try {
if (size < maxSize) {
push(value);
return heap[1];
} else {
if (value >= heap[1]) {
updateTop(value);
}
return heap[1];
}
} finally {
lock.unlock();
}
}

/**
* Inserts array of values into this heap.
*
* <p>Values must be sorted in ascending order.
*
* @param values a set of values to insert, must be sorted in ascending order
* @param len number of values from the {@code values} array to insert
* @return the new 'top' element in the queue.
*/
public float offer(float[] values, int len) {
if (len < 0 || len > values.length) {
throw new IllegalArgumentException(
"len must be in [0, values.length=" + values.length + "], got: " + len);
}
lock.lock();
try {
for (int i = len - 1; i >= 0; i--) {
if (size < maxSize) {
push(values[i]);
} else {
if (values[i] >= heap[1]) {
updateTop(values[i]);
} else {
break;
}
}
}
return heap[1];
} finally {
lock.unlock();
}
}

/**
* Removes and returns the head of the heap
*
* @return the head of the heap, the smallest value
* @throws IllegalStateException if the heap is empty
*/
public float poll() {
lock.lock();
try {
// The emptiness check must happen under the lock: checking outside lets two concurrent
// polls of a one-element heap both pass, and the second corrupts the heap state.
if (size > 0) {
float result = heap[1]; // save first value
heap[1] = heap[size]; // move last to first
size--;
downHeap(1); // adjust heap
return result;
} else {
throw new IllegalStateException("The heap is empty");
}
} finally {
lock.unlock();
}
}

/**
* Retrieves, but does not remove, the head of this heap.
*
* @return the head of the heap, the smallest value
*/
public float peek() {
lock.lock();
try {
return heap[1];
} finally {
lock.unlock();
}
}

/**
* Returns the number of elements in this heap.
*
* @return the number of elements in this heap
*/
public int size() {
lock.lock();
try {
return size;
} finally {
lock.unlock();
}
}

private void push(float element) {
size++;
heap[size] = element;
upHeap(size);
}

private float updateTop(float value) {
heap[1] = value;
downHeap(1);
return heap[1];
}

private void downHeap(int i) {
float value = heap[i]; // save top value
int j = i << 1; // find smaller child
int k = j + 1;
if (k <= size && heap[k] < heap[j]) {
j = k;
}
while (j <= size && heap[j] < value) {
heap[i] = heap[j]; // shift up child
i = j;
j = i << 1;
k = j + 1;
if (k <= size && heap[k] < heap[j]) {
j = k;
}
}
heap[i] = value; // install saved value
}

private void upHeap(int origPos) {
int i = origPos;
float value = heap[i]; // save bottom value
int j = i >>> 1;
while (j > 0 && value < heap[j]) {
heap[i] = heap[j]; // shift parents down
i = j;
j = j >>> 1;
}
heap[i] = value; // install saved value
}
}
Loading
Loading