Skip to content

Add bitmap64 query support#20606

Open
divyaruhil wants to merge 3 commits intoopensearch-project:mainfrom
divyaruhil:bitmap_64
Open

Add bitmap64 query support#20606
divyaruhil wants to merge 3 commits intoopensearch-project:mainfrom
divyaruhil:bitmap_64

Conversation

@divyaruhil
Copy link

@divyaruhil divyaruhil commented Feb 11, 2026

Description

Feature Request :- #20597

Related Issues

Resolves #20597

Check List

  • Functionality includes testing.
  • API changes companion pull request created, if applicable.
  • Public documentation issue/PR created, if applicable.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 11, 2026

📝 Walkthrough

Walkthrough

This pull request introduces 64-bit bitmap query support to OpenSearch by adding two new Lucene Query implementations (for index and doc values), integrating them into NumberFieldMapper for LONG numeric fields, and providing comprehensive test coverage for both query types.

Changes

Cohort / File(s) Summary
Mapper Integration
server/src/main/java/org/opensearch/index/mapper/NumberFieldMapper.java
Added bitmapQuery() override for LONG type that deserializes 64-bit Roaring bitmap from BytesArray and returns appropriate query type (IndexQuery, DocValuesQuery, or IndexOrDocValuesQuery) based on searchability and doc values availability.
64-bit Bitmap Index Query
server/src/main/java/org/opensearch/search/query/Bitmap64IndexQuery.java
New Query implementation for matching documents using 64-bit Roaring bitmap via point value intersection; includes weight creation with MergePointVisitor for efficient intersection, caching, equality, and memory accounting.
64-bit Bitmap DocValues Query
server/src/main/java/org/opensearch/search/query/Bitmap64DocValuesQuery.java
New Query implementation for matching documents using 64-bit Roaring bitmap via sorted numeric doc values; includes TwoPhaseIterator with optimized singleton path, weight creation, caching, equality, and memory accounting.
Query Tests
server/src/test/java/org/opensearch/search/query/Bitmap64DocValuesQueryTests.java, server/src/test/java/org/opensearch/search/query/Bitmap64IndexQueryTests.java
Test suites for both query types covering single/multi-value documents, empty bitmaps, range optimization, large values, null validation, and random document/query scenarios.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Mapper as NumberFieldMapper
    participant Deserializer as Bitmap Deserializer
    participant QueryFactory as Query Type Selector
    participant IndexQuery as Bitmap64IndexQuery
    participant DocValuesQuery as Bitmap64DocValuesQuery
    participant Searcher as IndexSearcher

    Client->>Mapper: bitmapQuery(field, BytesArray, isSearchable, hasDocValues)
    Mapper->>Deserializer: deserialize 64-bit Roaring bitmap
    Deserializer-->>Mapper: Roaring64NavigableMap
    
    alt isSearchable && hasDocValues
        Mapper->>QueryFactory: Create IndexOrDocValuesQuery
        QueryFactory->>IndexQuery: new Bitmap64IndexQuery(field, bitmap)
        QueryFactory->>DocValuesQuery: new Bitmap64DocValuesQuery(field, bitmap)
        QueryFactory-->>Mapper: IndexOrDocValuesQuery(indexQuery, docValuesQuery)
    else isSearchable
        Mapper->>IndexQuery: new Bitmap64IndexQuery(field, bitmap)
        IndexQuery-->>Mapper: IndexQuery
    else hasDocValues
        Mapper->>DocValuesQuery: new Bitmap64DocValuesQuery(field, bitmap)
        DocValuesQuery-->>Mapper: DocValuesQuery
    end
    
    Mapper-->>Client: Query
    Client->>Searcher: search(query)
    
    alt IndexQuery Path
        Searcher->>IndexQuery: createWeight()
        IndexQuery->>Searcher: PointValues ∩ Bitmap
        Searcher-->>Client: DocIdSet(matching docs)
    else DocValuesQuery Path
        Searcher->>DocValuesQuery: createWeight()
        DocValuesQuery->>Searcher: SortedNumericDocValues ∩ Bitmap
        Searcher-->>Client: DocIdSet(matching docs)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Suggested labels

enhancement, Indexing & Search, lucene

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The PR description references a feature request and resolves issue #20597, with tests included, but lacks detail on what the bitmap64 query feature actually does. Add a detailed description of the bitmap64 query feature, its purpose, use cases, and how it works to improve clarity for reviewers.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add bitmap64 query support' directly and concisely describes the main change: implementing bitmap64 query functionality. It is clear, specific, and directly relevant to all the changes in the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Contributor

❌ Gradle check result for 0dcc129: FAILURE

Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In `@server/src/main/java/org/opensearch/index/mapper/NumberFieldMapper.java`:
- Around line 1376-1399: The catch in NumberFieldMapper.bitmapQuery currently
catches Exception; change it to catch IOException (the declared exception from
deserializePortable) to avoid masking other errors—update the catch block in the
bitmapQuery method that deserializes into Roaring64NavigableMap to "catch
(IOException e)"; make the identical change in the INTEGER.bitmapQuery
deserialization catch as well; and add a short inline comment near both
bitmap64/bitmap32 usages (and the constructors for
Bitmap64IndexQuery/Bitmap64DocValuesQuery or where they are instantiated) noting
that the Roaring* bitmap is read-only after deserialization and must not be
modified by the query classes.

In
`@server/src/main/java/org/opensearch/search/query/Bitmap64DocValuesQuery.java`:
- Around line 1-3: Replace the short 3-line SPDX headers (or missing header) in
the new source and test files with the project's full 7-line header including
the OpenSearch contributor notice; specifically update the header comment at the
top of Bitmap64DocValuesQuery.java (class Bitmap64DocValuesQuery),
Bitmap64IndexQuery.java (class Bitmap64IndexQuery), and
Bitmap64IndexQueryTests.java (class Bitmap64IndexQueryTests) so they all start
with: "/*\n * SPDX-License-Identifier: Apache-2.0\n *\n * The OpenSearch
Contributors require contributions made to\n * this file be licensed under the
Apache-2.0 license or a\n * compatible open source license.\n */" ensuring exact
text and spacing to match existing project files.
- Around line 104-105: The code currently constructs a DefaultScorerSupplier
directly (e.g., in Bitmap64DocValuesQuery where you return new
DefaultScorerSupplier(scorer)); change these to use the fully-qualified nested
type Weight.DefaultScorerSupplier instead (return new
Weight.DefaultScorerSupplier(scorer)), and update all similar usages (e.g., in
BitmapDocValuesQuery, ShardSplittingQuery, etc.) so they reference
Weight.DefaultScorerSupplier rather than the unqualified DefaultScorerSupplier.

In
`@server/src/test/java/org/opensearch/search/query/Bitmap64IndexQueryTests.java`:
- Line 1: Add the missing SPDX license header to the top of the file for
Bitmap64IndexQueryTests: insert the same Apache-2.0 SPDX header block used in
other new files (for example Bitmap64DocValuesQueryTests) as the very first
lines of
server/src/test/java/org/opensearch/search/query/Bitmap64IndexQueryTests.java so
the file begins with the standard SPDX/Apache-2.0 header before the package
declaration and class definition.
🧹 Nitpick comments (7)
server/src/main/java/org/opensearch/search/query/Bitmap64IndexQuery.java (3)

29-29: Unused import: PeekableLongIterator is imported but never used.

Line 64 uses org.roaringbitmap.longlong.LongIterator directly. PeekableLongIterator (which extends LongIterator and adds advanceIfNeeded(long)) would actually be useful here — see next comment about advance() performance.


66-66: Inconsistent indentation: tab character mixed with spaces.

Line 66 uses a tab character for indentation while the rest of the file uses spaces.


141-208: MergePointVisitor is an inner class but could be static with the bitmap passed as a parameter.

MergePointVisitor is a non-static inner class that captures the enclosing Bitmap64IndexQuery instance solely to access bitmap. Making it static and passing bitmap to the constructor would make the dependency explicit and avoid retaining a reference to the entire query object.

That said, this mirrors the pattern used in the 32-bit BitmapIndexQuery, so it's consistent with the existing codebase.

server/src/test/java/org/opensearch/search/query/Bitmap64DocValuesQueryTests.java (2)

130-136: query.rewrite(null) relies on short-circuit before super.rewrite(null) is reached.

This works today because the empty-bitmap check returns early. If the implementation ever changes to invoke super before the check, this test will NPE. Consider creating a minimal IndexSearcher (e.g. from an empty directory) instead.


163-193: Consider adding a test with negative long values.

The current testLargeValues tests near Long.MAX_VALUE, which is great. However, there's no test for negative long values (e.g., Long.MIN_VALUE, negative ranges). Since LongPoint.encodeDimension uses an offset encoding that maps Long.MIN_VALUE → 0x0000... and Long.MAX_VALUE → 0xFFFF..., ensuring correct behavior across the signed boundary would strengthen coverage—especially for the doc-values path where min/max range checks (lines 71 and 86-88 in Bitmap64DocValuesQuery) must handle negative values correctly.

server/src/test/java/org/opensearch/search/query/Bitmap64IndexQueryTests.java (1)

76-99: Consider adding edge case tests for the index query path.

The random test is a good fuzz-style check, but explicit tests for edge cases would improve confidence:

  • Empty bitmap (verify rewrite to MatchNoDocsQuery)
  • Negative long values and values spanning the signed boundary (e.g., -1L, Long.MIN_VALUE)
  • equals/hashCode contract verification

The doc-values test file covers some of these for its query type, but the index path has a very different code path (BKD tree intersection) that warrants its own edge case coverage.

server/src/main/java/org/opensearch/search/query/Bitmap64DocValuesQuery.java (1)

30-30: Cross-class dependency for checkArgs validation.

Bitmap64DocValuesQuery imports checkArgs from Bitmap64IndexQuery. This creates a tight coupling where the doc-values query depends on the index query class for basic validation. This is minor but could be improved by either:

  • Extracting checkArgs into a shared utility (e.g., a Bitmap64QueryUtils class), or
  • Duplicating the trivial 2-line validation in each class.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between df38913 and 0dcc129.

📒 Files selected for processing (5)
  • server/src/main/java/org/opensearch/index/mapper/NumberFieldMapper.java
  • server/src/main/java/org/opensearch/search/query/Bitmap64DocValuesQuery.java
  • server/src/main/java/org/opensearch/search/query/Bitmap64IndexQuery.java
  • server/src/test/java/org/opensearch/search/query/Bitmap64DocValuesQueryTests.java
  • server/src/test/java/org/opensearch/search/query/Bitmap64IndexQueryTests.java
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-01-13T17:40:27.167Z
Learnt from: reta
Repo: opensearch-project/OpenSearch PR: 20411
File: server/src/main/java/org/opensearch/index/codec/CodecService.java:112-133
Timestamp: 2026-01-13T17:40:27.167Z
Learning: Avoid capturing or evaluating a supplier (e.g., this::defaultCodec) upfront when passing it to a registry during object construction. If registries may replace defaults during iteration (as in EnginePlugin.getAdditionalCodecs), pass the supplier itself and only resolve it at use time. This ensures dynamic behavior is preserved during initialization and prevents premature binding of defaults in codecs/registry setup. This pattern should apply to similar initialization paths in Java server code where registries may mutate defaults during construction.

Applied to files:

  • server/src/main/java/org/opensearch/index/mapper/NumberFieldMapper.java
  • server/src/main/java/org/opensearch/search/query/Bitmap64DocValuesQuery.java
  • server/src/main/java/org/opensearch/search/query/Bitmap64IndexQuery.java
🧬 Code graph analysis (2)
server/src/main/java/org/opensearch/index/mapper/NumberFieldMapper.java (2)
server/src/main/java/org/opensearch/search/query/Bitmap64IndexQuery.java (1)
  • Bitmap64IndexQuery (41-244)
server/src/main/java/org/opensearch/search/query/Bitmap64DocValuesQuery.java (1)
  • Bitmap64DocValuesQuery (36-155)
server/src/main/java/org/opensearch/search/query/Bitmap64DocValuesQuery.java (1)
server/src/main/java/org/opensearch/search/query/Bitmap64IndexQuery.java (1)
  • Bitmap64IndexQuery (41-244)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: gradle-check
🔇 Additional comments (7)
server/src/main/java/org/opensearch/search/query/Bitmap64IndexQuery.java (3)

99-139: LGTM — createWeight implementation looks correct.

The weight creates a scorer supplier that uses BKD tree intersection with the merge-sort style MergePointVisitor. The cost heuristic (cardinality × 20) matches the 32-bit version. Returning null when values == null correctly signals no matching docs for the segment. Caching is set to true since the query depends only on the immutable segment point values and the bitmap.


210-243: LGTM — rewrite, equals, hashCode, ramBytesUsed look correct.

Empty bitmap rewrites to MatchNoDocsQuery. Equality and hashing delegate to the field and bitmap. RAM usage accounts for the query instance, the field string, and the bitmap's internal memory.


62-97: The suggested optimization cannot be applied to Roaring64NavigableMap.

Roaring64NavigableMap#getLongIterator() returns LongIterator, not PeekableLongIterator. The PeekableLongIterator interface with the advanceIfNeeded() method is only available in Roaring64Bitmap, not Roaring64NavigableMap. Applying this suggestion would fail at compile or runtime because the types are incompatible.

To use this optimization, the code would need to either change the input type from Roaring64NavigableMap to Roaring64Bitmap, or use Roaring64Bitmap#getLongIteratorFrom(long minval) which directly accepts a target value. Neither is feasible here without changing the public API of Bitmap64IndexQuery.

Likely an incorrect or invalid review comment.

server/src/test/java/org/opensearch/search/query/Bitmap64DocValuesQueryTests.java (1)

32-219: Good test coverage for the doc-values query path.

The tests cover single-value, multi-value, empty bitmap, rewrite, range, large values, and null-argument validation. This provides solid baseline coverage.

server/src/test/java/org/opensearch/search/query/Bitmap64IndexQueryTests.java (1)

18-138: Overall test structure looks good.

The @Before/@After lifecycle management, the refresh() helper, and the getMatchingValues() extraction utility are well-structured. The tests correctly validate both single-value and multi-value document scenarios.

server/src/main/java/org/opensearch/search/query/Bitmap64DocValuesQuery.java (2)

56-113: createWeight implementation is well-structured.

The singleton vs. multi-value path distinction, the [min, max] range guard before the bitmap.contains() call, and the early termination in the multi-value loop (leveraging SortedNumericDocValues ascending order guarantee) are all correct and efficient. The matchCost() of 5 is a reasonable constant consistent with the 32-bit counterpart.


120-126: LGTM — empty bitmap rewrite.

Correctly short-circuits to MatchNoDocsQuery for empty bitmaps, avoiding unnecessary scorer creation.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines 1376 to 1399
@Override
public Query bitmapQuery(String field, BytesArray bitmapArray, boolean isSearchable, boolean hasDocValues) {
// Extract bytes safely
BytesRef ref = bitmapArray.toBytesRef();
byte[] bytes = Arrays.copyOfRange(ref.bytes, ref.offset, ref.offset + ref.length);

Roaring64NavigableMap bitmap64 = new Roaring64NavigableMap();
try {
bitmap64.deserializePortable(new DataInputStream(new ByteArrayInputStream(bytes)));
} catch (Exception e) {
throw new IllegalArgumentException("Failed to deserialize the 64-bit bitmap.", e);
}

if (isSearchable && hasDocValues) {
return new IndexOrDocValuesQuery(
new Bitmap64IndexQuery(field, bitmap64),
new Bitmap64DocValuesQuery(field, bitmap64)
);
}
if (isSearchable) {
return new Bitmap64IndexQuery(field, bitmap64);
}
return new Bitmap64DocValuesQuery(field, bitmap64);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's check the INTEGER.bitmapQuery implementation to compare patterns
grep -A 30 "INTEGER.bitmapQuery" /dev/stdin << 'EOF'
Looking at line 1168 and surrounding context in NumberFieldMapper.java
EOF

# Let's search for the INTEGER case in the file
rg -A 30 "case INTEGER:" server/src/main/java/org/opensearch/index/mapper/NumberFieldMapper.java | head -50

Repository: opensearch-project/OpenSearch

Length of output: 116


🌐 Web query:

Roaring64NavigableMap mutability thread safety RoaringBitmap

💡 Result:

  • Mutability: Roaring64NavigableMap is mutable. It has in-place mutators like add…, addRange…, clear(), and(...), andNot(...), etc. (so it is not an immutable/persistent data structure). [1]

  • Thread safety (general RoaringBitmap Java guidance): Roaring bitmaps (including Roaring64NavigableMap) are not synchronized; it is unsafe to access the same bitmap concurrently from multiple threads if any thread may mutate it. If you need multi-thread access, you must provide external synchronization, or use per-thread copies. [2]

  • Read-only sharing: You can safely share a bitmap across threads only if it is not being modified (i.e., effectively immutable for the duration of sharing). This same “safe as long as unchanged” rule is also stated for several static operations in the library Javadocs. [3]

Practical rule: treat Roaring64NavigableMap as mutable + not thread-safe; share only for concurrent reads, and otherwise synchronize or copy per thread. [1][2]

References:
[1] Roaring64NavigableMap Javadoc (methods like add, clear, and, andNot) https://www.javadoc.io/static/org.roaringbitmap/RoaringBitmap/1.2.0/roaringbitmap/org/roaringbitmap/longlong/Roaring64NavigableMap.html
[2] RoaringBitmap GitHub README — “Thread safety” section https://github.com/RoaringBitmap/RoaringBitmap
[3] RoaringBitmap Javadoc (examples noting operations are thread-safe if inputs remain unchanged) https://javadoc.io/static/org.roaringbitmap/RoaringBitmap/0.8.1/org/roaringbitmap/RoaringBitmap.html


🌐 Web query:

RoaringBitmap deserializePortable IOException API exceptions

💡 Result:

In the Java RoaringBitmap API, deserializePortable(...) is declared to throw only java.io.IOException (a checked exception). For example, Roaring64NavigableMap.deserializePortable(DataInput in) has the signature throws IOException. [1]

What that means in practice:

  • You only need to catch/declare IOException for the portable deserialization call site. [1]
  • The concrete IOException you actually see depends on the underlying DataInput implementation:
    • If the serialized data is truncated, DataInput methods can throw EOFException (a subclass of IOException). [2]
    • Other read failures will surface as other IOException subclasses from the underlying stream. [2]

Important: IOException is about I/O/read failures, not necessarily “bad bitmap contents”. If you are deserializing untrusted or potentially corrupted bytes, RoaringBitmap’s own docs recommend validating after deserialization (e.g., validate() for RoaringBitmap) to ensure the internal structure is sane. [3]

Sources: [1] RoaringBitmap Javadoc (deserializePortable signature/throws) (javadoc.io), [2] Oracle DataInput Javadoc (EOFException/IOException behavior) (docs.oracle.com), [3] RoaringBitmap repo README (recommend validate() after deserialize for untrusted data) (github.com)

Citations:


🏁 Script executed:

rg "case INTEGER" server/src/main/java/org/opensearch/index/mapper/NumberFieldMapper.java -A 40 | head -60

Repository: opensearch-project/OpenSearch

Length of output: 55


🏁 Script executed:

# Let's also verify what happens in Bitmap64IndexQuery and Bitmap64DocValuesQuery
# to understand if the shared bitmap could be modified
rg -l "class Bitmap64IndexQuery|class Bitmap64DocValuesQuery" server/src/main/java/org/opensearch/index/mapper/

Repository: opensearch-project/OpenSearch

Length of output: 55


🏁 Script executed:

# Search for Bitmap64IndexQuery and Bitmap64DocValuesQuery definitions
rg "class Bitmap64IndexQuery|class Bitmap64DocValuesQuery" --type java

Repository: opensearch-project/OpenSearch

Length of output: 664


🏁 Script executed:

# Also search for the INTEGER case more carefully
rg "INTEGER\s*\.\s*bitmapQuery" server/src/main/java/org/opensearch/index/mapper/NumberFieldMapper.java -B 5 -A 20

Repository: opensearch-project/OpenSearch

Length of output: 55


🏁 Script executed:

# Let's read the full context around lines 1376-1399 and compare with INTEGER implementation
cat -n server/src/main/java/org/opensearch/index/mapper/NumberFieldMapper.java | sed -n '1150,1200p'

Repository: opensearch-project/OpenSearch

Length of output: 2642


🏁 Script executed:

# Read the Bitmap64IndexQuery implementation
cat -n server/src/main/java/org/opensearch/search/query/Bitmap64IndexQuery.java

Repository: opensearch-project/OpenSearch

Length of output: 10416


🏁 Script executed:

# Read the Bitmap64DocValuesQuery implementation
cat -n server/src/main/java/org/opensearch/search/query/Bitmap64DocValuesQuery.java

Repository: opensearch-project/OpenSearch

Length of output: 6467


🏁 Script executed:

# Also check BitmapIndexQuery and BitmapDocValuesQuery (INTEGER versions) for comparison
fd "BitmapIndexQuery.java|BitmapDocValuesQuery.java" --type f | grep -v "Bitmap64" | head -5

Repository: opensearch-project/OpenSearch

Length of output: 218


🏁 Script executed:

# Let's verify that the INTEGER.bitmapQuery exception handling and check BitmapIndexQuery/BitmapDocValuesQuery
cat -n server/src/main/java/org/opensearch/search/query/BitmapIndexQuery.java | head -100

Repository: opensearch-project/OpenSearch

Length of output: 4288


🏁 Script executed:

# Check if IOException is declared in method signatures for deserialize
rg "deserialize" server/src/main/java/org/opensearch/search/query/Bitmap64IndexQuery.java

Repository: opensearch-project/OpenSearch

Length of output: 55


Catch only IOException for deserialization, not generic Exception.

The deserializePortable() method declares throws IOException. Catching the broader Exception is imprecise and masks the true exception type. Change line 1385 to catch IOException (which includes EOFException for truncated data).

Note: The same overly broad exception handling exists in INTEGER.bitmapQuery() at line 1169 and should be corrected there as well.

Regarding the shared bitmap64 instance between Bitmap64IndexQuery and Bitmap64DocValuesQuery: this is safe in practice because both query classes perform only read-only operations (contains(), first(), last(), isEmpty()) on the bitmap after deserialization. However, this pattern (also present in the 32-bit INTEGER.bitmapQuery()) could benefit from a code comment clarifying that the bitmap must not be modified post-deserialization.

🤖 Prompt for AI Agents
In `@server/src/main/java/org/opensearch/index/mapper/NumberFieldMapper.java`
around lines 1376 - 1399, The catch in NumberFieldMapper.bitmapQuery currently
catches Exception; change it to catch IOException (the declared exception from
deserializePortable) to avoid masking other errors—update the catch block in the
bitmapQuery method that deserializes into Roaring64NavigableMap to "catch
(IOException e)"; make the identical change in the INTEGER.bitmapQuery
deserialization catch as well; and add a short inline comment near both
bitmap64/bitmap32 usages (and the constructors for
Bitmap64IndexQuery/Bitmap64DocValuesQuery or where they are instantiated) noting
that the Roaring* bitmap is read-only after deserialization and must not be
modified by the query classes.

Comment on lines 1 to 3
/*
* SPDX-License-Identifier: Apache-2.0
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check license headers across the new bitmap64 files
echo "=== Bitmap64DocValuesQuery.java ==="
head -10 server/src/main/java/org/opensearch/search/query/Bitmap64DocValuesQuery.java

echo ""
echo "=== Bitmap64IndexQuery.java ==="
head -10 server/src/main/java/org/opensearch/search/query/Bitmap64IndexQuery.java

echo ""
echo "=== Bitmap64DocValuesQueryTests.java ==="
head -10 server/src/test/java/org/opensearch/search/query/Bitmap64DocValuesQueryTests.java

echo ""
echo "=== Bitmap64IndexQueryTests.java ==="
head -10 server/src/test/java/org/opensearch/search/query/Bitmap64IndexQueryTests.java

echo ""
echo "=== Reference: existing BitmapDocValuesQuery.java header ==="
head -10 server/src/main/java/org/opensearch/search/query/BitmapDocValuesQuery.java

Repository: opensearch-project/OpenSearch

Length of output: 1706


Inconsistent and missing SPDX license headers across new files.

The new source files use a short 3-line SPDX header, while test files and the existing BitmapDocValuesQuery.java reference file use the full 7-line header with the OpenSearch contributor requirement notice. Additionally, Bitmap64IndexQueryTests.java is missing a license header entirely. Align all new files to use the full header format for consistency with the project standard:

/*
 * SPDX-License-Identifier: Apache-2.0
 *
 * The OpenSearch Contributors require contributions made to
 * this file be licensed under the Apache-2.0 license or a
 * compatible open source license.
 */

Apply this to Bitmap64DocValuesQuery.java, Bitmap64IndexQuery.java, and Bitmap64IndexQueryTests.java.

🤖 Prompt for AI Agents
In `@server/src/main/java/org/opensearch/search/query/Bitmap64DocValuesQuery.java`
around lines 1 - 3, Replace the short 3-line SPDX headers (or missing header) in
the new source and test files with the project's full 7-line header including
the OpenSearch contributor notice; specifically update the header comment at the
top of Bitmap64DocValuesQuery.java (class Bitmap64DocValuesQuery),
Bitmap64IndexQuery.java (class Bitmap64IndexQuery), and
Bitmap64IndexQueryTests.java (class Bitmap64IndexQueryTests) so they all start
with: "/*\n * SPDX-License-Identifier: Apache-2.0\n *\n * The OpenSearch
Contributors require contributions made to\n * this file be licensed under the
Apache-2.0 license or a\n * compatible open source license.\n */" ensuring exact
text and spacing to match existing project files.

Comment on lines 104 to 105
final Scorer scorer = new ConstantScoreScorer(score(), scoreMode, iterator);
return new DefaultScorerSupplier(scorer);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Check for DefaultScorerSupplier usage and imports in the codebase
rg "DefaultScorerSupplier" --type java -C 2

Repository: opensearch-project/OpenSearch

Length of output: 11146


🏁 Script executed:

# Find the Lucene version being used
fd "pom.xml" | head -5 | xargs grep -l "lucene" 2>/dev/null | head -3

Repository: opensearch-project/OpenSearch

Length of output: 55


🏁 Script executed:

# Check the specific file for imports and context
cat -n server/src/main/java/org/opensearch/search/query/Bitmap64DocValuesQuery.java | sed -n '1,120p'

Repository: opensearch-project/OpenSearch

Length of output: 5236


🏁 Script executed:

# Check for wildcard imports and all imports in the file
cat server/src/main/java/org/opensearch/search/query/Bitmap64DocValuesQuery.java | head -30

Repository: opensearch-project/OpenSearch

Length of output: 1140


🏁 Script executed:

# Search for where DefaultScorerSupplier is imported from
rg "import.*DefaultScorerSupplier" --type java

Repository: opensearch-project/OpenSearch

Length of output: 55


🏁 Script executed:

# Check if it's in a wildcard import - look at a file that uses it
cat server/src/main/java/org/opensearch/search/query/BitmapDocValuesQuery.java | head -40

Repository: opensearch-project/OpenSearch

Length of output: 1369


🏁 Script executed:

# Find the Lucene version in pom.xml
find . -name "pom.xml" -type f | xargs grep -l "lucene" | head -1 | xargs cat | grep -A 5 -B 5 "lucene.version\|<lucene>" | head -30

Repository: opensearch-project/OpenSearch

Length of output: 55


🏁 Script executed:

# Search for the class definition of DefaultScorerSupplier
rg "class DefaultScorerSupplier" --type java

Repository: opensearch-project/OpenSearch

Length of output: 55


🏁 Script executed:

# Look for any file that might define DefaultScorerSupplier in OpenSearch
fd "DefaultScorerSupplier.java"

Repository: opensearch-project/OpenSearch

Length of output: 55


🏁 Script executed:

# Check the main pom.xml for Lucene version
find . -maxdepth 2 -name "pom.xml" -exec grep -H "lucene" {} \; | head -20

Repository: opensearch-project/OpenSearch

Length of output: 55


🏁 Script executed:

# Also check build.gradle files
fd "build.gradle" -x grep -l "lucene" {} \;

Repository: opensearch-project/OpenSearch

Length of output: 561


🏁 Script executed:

# Check server build.gradle for Lucene version
cat ./server/build.gradle | grep -A 5 -B 5 "lucene\|org.apache.lucene" | head -50

Repository: opensearch-project/OpenSearch

Length of output: 1635


🏁 Script executed:

# Try a broader search for where DefaultScorerSupplier could come from
rg "DefaultScorerSupplier" --type java -B 5 | grep -E "import|class|package" | head -30

Repository: opensearch-project/OpenSearch

Length of output: 55


🌐 Web query:

Lucene DefaultScorerSupplier class availability

💡 Result:

DefaultScorerSupplier is not a standalone public class in Lucene. In current Lucene it exists as a nested, protected class:

  • Name / location: org.apache.lucene.search.Weight.DefaultScorerSupplier (nested inside Weight) and marked internal-only (“might change in incompatible ways”). [1]
  • Availability: Present in Lucene 10.x (it appears in the Weight nested class summary starting with Lucene 10.0.0). [2]
  • Not present in Lucene 9.x / 8.x: The Weight nested classes in those versions list DefaultBulkScorer (and other helpers) but do not include DefaultScorerSupplier. [3]

Implication: if you’re on Lucene 9.x or earlier, you won’t find it; on 10.x you can only reference it as Weight.DefaultScorerSupplier, and only where protected access allows. [1][2]

Sources:
[1] Lucene 10.2.1 Javadoc: Weight.DefaultScorerSupplier
[2] Lucene 10.0.0 Javadoc: Weight nested class summary includes Weight.DefaultScorerSupplier
[3] Lucene 8.9.0 Javadoc: Weight nested class summary does not include DefaultScorerSupplier


🏁 Script executed:

# Find Lucene version in gradle files
fd "gradle.properties" -o "settings.gradle" | xargs cat | grep -i lucene | head -20

Repository: opensearch-project/OpenSearch

Length of output: 222


🏁 Script executed:

# Check if OpenSearch defines its own DefaultScorerSupplier
rg "class DefaultScorerSupplier" --type java -A 3

Repository: opensearch-project/OpenSearch

Length of output: 55


🏁 Script executed:

# Look for Weight.DefaultScorerSupplier usage (proper Lucene reference)
rg "Weight\.DefaultScorerSupplier" --type java

Repository: opensearch-project/OpenSearch

Length of output: 55


🏁 Script executed:

# Check if there's a local/private DefaultScorerSupplier in opensearch.search.query package or common locations
fd DefaultScorerSupplier --type f

Repository: opensearch-project/OpenSearch

Length of output: 55


🏁 Script executed:

# Find gradle.properties correctly
find . -name "gradle.properties" -type f | head -5 | xargs cat | grep -i lucene

Repository: opensearch-project/OpenSearch

Length of output: 55


🏁 Script executed:

# Look in the root for version info
cat gradle.properties 2>/dev/null | head -50

Repository: opensearch-project/OpenSearch

Length of output: 1435


🏁 Script executed:

# Check the actual imports and source more carefully - maybe it's a wildcard or re-export
ast-grep --pattern 'import org.apache.lucene.search.*' | head -20

Repository: opensearch-project/OpenSearch

Length of output: 187


🏁 Script executed:

# Look at the compiled code structure - check if there's any DefaultScorerSupplier anywhere
find . -type f -name "*.java" | xargs grep -l "DefaultScorerSupplier" | xargs grep -B 10 "class.*Weight\|interface.*ScorerSupplier" | head -40

Repository: opensearch-project/OpenSearch

Length of output: 1534


🏁 Script executed:

# Check for lucene version more broadly in build files
find . -name "build.gradle*" -o -name "pom.xml" | head -10 | xargs grep -h "lucene" | grep -i "version\|=" | head -20

Repository: opensearch-project/OpenSearch

Length of output: 55


🏁 Script executed:

# Look at the libs configuration in gradle
cat libs.versions.toml 2>/dev/null | grep -i lucene

Repository: opensearch-project/OpenSearch

Length of output: 55


🏁 Script executed:

# Check OpenSearch's approach - maybe they provide DefaultScorerSupplier as a utility
find . -path "*/lucene/*" -name "*.java" | xargs grep -l "DefaultScorerSupplier" 2>/dev/null | head -5

Repository: opensearch-project/OpenSearch

Length of output: 402


🏁 Script executed:

# Double-check the exact file again - does it compile without the import?
cat -n server/src/main/java/org/opensearch/search/query/Bitmap64DocValuesQuery.java | grep -A 50 "^[ ]*1"

Repository: opensearch-project/OpenSearch

Length of output: 4939


🏁 Script executed:

# Check one of the other files that uses DefaultScorerSupplier
cat -n server/src/main/java/org/opensearch/lucene/queries/MinDocQuery.java | head -50

Repository: opensearch-project/OpenSearch

Length of output: 2161


🏁 Script executed:

# Search for any local DefaultScorerSupplier definition or wrapper in opensearch codebase
rg "DefaultScorerSupplier" --type java -B 3 -A 3 | grep -E "^[^-].*package|^[^-].*class|^[^-].*interface" | head -20

Repository: opensearch-project/OpenSearch

Length of output: 55


🏁 Script executed:

# Check what version of Lucene is actually being used by looking at gradle dependencies more carefully
find . -name "gradle" -o -name "build.gradle" | xargs grep -l "lucene\|elasticsearch" 2>/dev/null | head -3 | xargs cat | grep -E "dependencies|lucene|version" | head -30

Repository: opensearch-project/OpenSearch

Length of output: 680


🌐 Web query:

OpenSearch Lucene version 2024 2025

💡 Result:

OpenSearch’s embedded Apache Lucene versions around 2024–2025 (by OpenSearch release line):

  • OpenSearch 2.13 / 2.14 / 2.15 (2024)Lucene 9.10.0. [1]
  • OpenSearch 2.16 / 2.17 (2024)Lucene 9.11.1. [2]
  • OpenSearch 2.18 (2024)Lucene 9.12.0. [3]
  • OpenSearch 2.19.x (released Feb 11, 2025)Lucene 9.12.1. [4]
  • OpenSearch 3.0.0 (released May 6, 2025)Lucene 10.1.0 (Lucene 10 major upgrade). [5][6]

Sources:
[1] OpenSearch 2.13.0 GitHub release notes (dependency: “Bump Apache Lucene from 9.9.2 to 9.10.0”)
[2] OpenSearch 2.16.0 GitHub release notes (dependency: “Update to Apache Lucene 9.11.1”)
[3] OpenSearch 2.18.0 GitHub release notes (dependency: “Bump Apache lucene from 9.11.1 to 9.12.0”)
[4] Maven artifact metadata for org.opensearch:opensearch-core:2.19.0 (depends on lucene-core:9.12.1)
[5] OpenSearch 3.0.0 GitHub release notes (breaking change: “Upgrade to Lucene 10.1.0”)
[6] OpenSearch documentation “Version history” (3.0.0: “Upgrades to Lucene 10…”, release date May 6, 2025)


🏁 Script executed:

# Check the OpenSearch version in the repo
cat gradle.properties | grep -i "version\|opensearch" | head -10

Repository: opensearch-project/OpenSearch

Length of output: 314


🏁 Script executed:

# Also check the build.gradle in libs/core which defines lucene version
cat libs/core/build.gradle | grep -E "lucene|version" | head -20

Repository: opensearch-project/OpenSearch

Length of output: 543


🏁 Script executed:

# Check the versions.properties or similar for lucene version
find . -maxdepth 3 -name "versions.properties" -o -name "versions.gradle" | xargs cat 2>/dev/null | grep -i lucene

Repository: opensearch-project/OpenSearch

Length of output: 55


🏁 Script executed:

# Most direct approach - check what version of lucene-core the build uses
find . -name "build.gradle" -type f | xargs grep -h "lucene.core\|lucene-core" | head -10

Repository: opensearch-project/OpenSearch

Length of output: 153


🏁 Script executed:

# Find the versions catalog or versions file
find . -maxdepth 3 -name "*.toml" -o -name "*.gradle" -o -name "*.properties" | xargs grep -l "lucene.*=" 2>/dev/null | head -5

Repository: opensearch-project/OpenSearch

Length of output: 100


🏁 Script executed:

# Check gradle/libs.versions.toml which is the standard location
cat gradle/libs.versions.toml 2>/dev/null | grep -A 2 -B 2 lucene

Repository: opensearch-project/OpenSearch

Length of output: 2328


🏁 Script executed:

# Or check if it's in build.gradle
find . -maxdepth 1 -name "build.gradle" | xargs cat | grep -A 5 "versions\s*{" | head -30

Repository: opensearch-project/OpenSearch

Length of output: 55


🏁 Script executed:

# Check settings.gradle for version catalog
cat settings.gradle 2>/dev/null | grep -A 50 "versionCatalogs\|dependencyResolutionManagement"

Repository: opensearch-project/OpenSearch

Length of output: 55


🌐 Web query:

Lucene 10.3.2 DefaultScorerSupplier public class

💡 Result:

In Lucene 10.3.2, there is no public top-level class named DefaultScorerSupplier.

What you’re looking for is the nested class:

  • org.apache.lucene.search.Weight.DefaultScorerSupplier

and it is protected static final (ie, not public and not instantiable/accessible from arbitrary application code). It’s explicitly marked as internal API. [1], [2]

If your goal is to create/return a scorer supplier in your own query/weight, use the public API surface (Weight#scorerSupplier(...) returning a ScorerSupplier implementation) rather than trying to reference Weight.DefaultScorerSupplier. [2]

Sources

[1] Lucene 10.3.2 org.apache.lucene.search package summary (lists Weight.DefaultScorerSupplier)
[2] Lucene Weight / Weight.DefaultScorerSupplier javadocs showing it as protected static final and internal API


🏁 Script executed:

# Check if maybe there's a custom wrapper or if it's re-exported
rg "DefaultScorerSupplier" --type java | grep -E "extends|implements|class.*DefaultScorerSupplier" | head -10

Repository: opensearch-project/OpenSearch

Length of output: 55


🏁 Script executed:

# Verify the file actually compiles by checking if it's in test or actual source
git log --oneline server/src/main/java/org/opensearch/search/query/Bitmap64DocValuesQuery.java 2>/dev/null | head -5

Repository: opensearch-project/OpenSearch

Length of output: 108


🏁 Script executed:

# Check if there are any compilation errors or build issues reported
find . -name "build.gradle" -type f -path "*/server/*" | head -1 | xargs grep -A 10 "compileJava\|tasks.named.*compile"

Repository: opensearch-project/OpenSearch

Length of output: 497


🏁 Script executed:

# Check if maybe OpenSearch provides a shim or utility for DefaultScorerSupplier
rg "class.*DefaultScorerSupplier\|object.*DefaultScorerSupplier" --type java -A 5

Repository: opensearch-project/OpenSearch

Length of output: 55


🏁 Script executed:

# Verify the exact import behavior - maybe there's a package-private access or factory
cat server/src/main/java/org/opensearch/search/query/Bitmap64DocValuesQuery.java | grep -E "^import|^package|DefaultScorerSupplier"

Repository: opensearch-project/OpenSearch

Length of output: 1147


🌐 Web query:

Lucene 10 Weight DefaultScorerSupplier how to use create ScorerSupplier

💡 Result:

In Lucene 10, Weight.scorerSupplier(LeafReaderContext) is abstract, so custom Weight implementations must return a ScorerSupplier (or null if no matches). The simplest way is to build a Scorer immediately and wrap it in Weight.DefaultScorerSupplier. [1]

Minimal pattern (use Weight.DefaultScorerSupplier)

`@Override`
public ScorerSupplier scorerSupplier(LeafReaderContext ctx) throws IOException {
  Scorer scorer = buildScorer(ctx);   // your scorer creation
  if (scorer == null) return null;    // required contract
  return new Weight.DefaultScorerSupplier(scorer);
}

Weight.DefaultScorerSupplier is just a small wrapper around an already-built Scorer and provides cost() and get(long leadCost). [2]

Lazy pattern (implement ScorerSupplier yourself)

If building the scorer is expensive and you want to:

  • expose a cheap cost() up front, and/or
  • use leadCost to choose an implementation,

then implement ScorerSupplier:

`@Override`
public ScorerSupplier scorerSupplier(LeafReaderContext ctx) throws IOException {
  long cost = estimatedCost(ctx);

  return new ScorerSupplier() {
    private Scorer scorer; // build at most once

    `@Override`
    public long cost() {
      return cost;
    }

    `@Override`
    public Scorer get(long leadCost) throws IOException {
      if (scorer == null) {
        scorer = buildScorerConsideringLeadCost(ctx, leadCost);
      }
      return scorer; // must be non-null and get() must be called at most once
    }
  };
}

Notes:

  • ScorerSupplier.get(long leadCost) must be called at most once and must not return null. [2]
  • If unsure what to do with leadCost, treat it as “how iteration-heavy the caller expects things to be” and ignore it (or behave as if it were Long.MAX_VALUE). [2][3]

Sources: Weight.scorerSupplier(...) contract and bulkScorer() delegation [1]; Weight.DefaultScorerSupplier API and get/cost behavior [2]; ScorerSupplier role/shape [3].

[1] (lucene.apache.org)
[2] (lucene.apache.org)
[3] (lucene.apache.org)

Citations:


Use fully qualified class name Weight.DefaultScorerSupplier.

DefaultScorerSupplier is a protected nested class in Lucene 10.3.2 (Weight.DefaultScorerSupplier), not a standalone public class. It must be referenced with its qualifying class name. Change line 105 from:

return new DefaultScorerSupplier(scorer);

to:

return new Weight.DefaultScorerSupplier(scorer);

This applies to all similar usages throughout the codebase (BitmapDocValuesQuery, ShardSplittingQuery, and others).

🤖 Prompt for AI Agents
In `@server/src/main/java/org/opensearch/search/query/Bitmap64DocValuesQuery.java`
around lines 104 - 105, The code currently constructs a DefaultScorerSupplier
directly (e.g., in Bitmap64DocValuesQuery where you return new
DefaultScorerSupplier(scorer)); change these to use the fully-qualified nested
type Weight.DefaultScorerSupplier instead (return new
Weight.DefaultScorerSupplier(scorer)), and update all similar usages (e.g., in
BitmapDocValuesQuery, ShardSplittingQuery, etc.) so they reference
Weight.DefaultScorerSupplier rather than the unqualified DefaultScorerSupplier.

@@ -0,0 +1,139 @@
package org.opensearch.search.query;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Missing SPDX license header.

This file is missing the SPDX license header that other new files in this PR include (e.g., Bitmap64DocValuesQueryTests.java has the full Apache-2.0 header block).

🤖 Prompt for AI Agents
In
`@server/src/test/java/org/opensearch/search/query/Bitmap64IndexQueryTests.java`
at line 1, Add the missing SPDX license header to the top of the file for
Bitmap64IndexQueryTests: insert the same Apache-2.0 SPDX header block used in
other new files (for example Bitmap64DocValuesQueryTests) as the very first
lines of
server/src/test/java/org/opensearch/search/query/Bitmap64IndexQueryTests.java so
the file begins with the standard SPDX/Apache-2.0 header before the package
declaration and class definition.

@github-actions
Copy link
Contributor

❌ Gradle check result for a0e6ef7: FAILURE

Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?

@divyaruhil
Copy link
Author

divyaruhil commented Feb 12, 2026

The Gradle Check failure is in

> Task :server:test

Tests with failures:
 - org.opensearch.cluster.routing.remote.RemoteRoutingTableServiceTests.testGetAsyncIndexRoutingTableDiffReadAction

, which appears to be a known Flaky Test 14559

This test passes consistently locally, including with --rerun-tasks.

Divya and others added 3 commits February 12, 2026 06:48
Signed-off-by: Divya <DIVYA2@ibm.com>
Signed-off-by: Divya <divyaruhil999@gmail.com>
Signed-off-by: Divya <divyaruhil999@gmail.com>
Signed-off-by: Divya <divyaruhil999@gmail.com>
@divyaruhil
Copy link
Author

Hi @andrross @anasalkouz @saratvemulapalli @epugh @kyleconroy I was excited to work on this and have raised the PR. Whenever you get a chance, I’d appreciate a review. I’m happy to update anything based on your suggestions. Thank you!

@github-actions
Copy link
Contributor

✅ Gradle check result for c598688: SUCCESS

@codecov
Copy link

codecov bot commented Feb 12, 2026

Codecov Report

❌ Patch coverage is 75.16779% with 37 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.37%. Comparing base (e59c30c) to head (c598688).
⚠️ Report is 21 commits behind head on main.

Files with missing lines Patch % Lines
...rg/opensearch/search/query/Bitmap64IndexQuery.java 81.11% 9 Missing and 8 partials ⚠️
...org/opensearch/index/mapper/NumberFieldMapper.java 0.00% 12 Missing ⚠️
...pensearch/search/query/Bitmap64DocValuesQuery.java 82.97% 5 Missing and 3 partials ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main   #20606      +/-   ##
============================================
- Coverage     73.37%   73.37%   -0.01%     
- Complexity    72197    72219      +22     
============================================
  Files          5798     5800       +2     
  Lines        329816   329967     +151     
  Branches      47538    47565      +27     
============================================
+ Hits         242001   242097      +96     
- Misses        68458    68476      +18     
- Partials      19357    19394      +37     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Enhancement or improvement to existing feature or request Search:Query Capabilities

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature Request] 64-bit roaring bitmap support

1 participant