-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Fix CriteriaBasedCodec to work with delegate codec #20442
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,145 @@ | ||
| /* | ||
| * 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. | ||
| */ | ||
|
|
||
| package org.opensearch.index.codec; | ||
|
|
||
| import org.apache.lucene.codecs.FieldsConsumer; | ||
| import org.apache.lucene.codecs.FieldsProducer; | ||
| import org.apache.lucene.codecs.NormsProducer; | ||
| import org.apache.lucene.codecs.PostingsFormat; | ||
| import org.apache.lucene.index.FieldInfo; | ||
| import org.apache.lucene.index.Fields; | ||
| import org.apache.lucene.index.MergeState; | ||
| import org.apache.lucene.index.SegmentReadState; | ||
| import org.apache.lucene.index.SegmentWriteState; | ||
|
|
||
| import java.io.IOException; | ||
| import java.util.Set; | ||
| import java.util.stream.Collectors; | ||
| import java.util.stream.StreamSupport; | ||
|
|
||
| import static org.opensearch.index.codec.CriteriaBasedCodec.ATTRIBUTE_BINDING_TARGET_FIELD; | ||
|
|
||
| /** | ||
| * Postings format to attach segment info attribute corresponding to grouping criteria associated with segments. | ||
| * | ||
| */ | ||
| public class CriteriaBasedPostingsFormat extends PostingsFormat { | ||
|
|
||
| public static final String CRITERIA_BASED_CODEC_NAME = "CriteriaBasedCodec99"; | ||
| private final PostingsFormat delegatePostingsFormat; | ||
| private final String bucket; | ||
| /** Extension of CAS index to store delegate information. */ | ||
| public static final String CAS_FILE_EXTENSION = "cas"; | ||
| public static final int VERSION_START = 0; | ||
| public static final int VERSION_CURRENT = VERSION_START; | ||
| public static final String BUCKET_NAME = "bucket"; | ||
| private static final String PLACEHOLDER_BUCKET_FOR_PARENT_WRITER = "-2"; | ||
| private static final String DELEGATE_CODEC_KEY = "delegate_codec_key"; | ||
|
|
||
| /** | ||
| * Creates a new postings format. | ||
| * | ||
| * <p>The provided name will be written into the index segment in some configurations (such as | ||
| * when using ): in such configurations, for the segment to be read | ||
| * this class should be registered with Java's SPI mechanism (registered in META-INF/ of your jar | ||
| * file, etc). | ||
| * | ||
| */ | ||
| protected CriteriaBasedPostingsFormat(PostingsFormat delegatePostingsFormat, String bucket) { | ||
| super(CRITERIA_BASED_CODEC_NAME); | ||
| this.delegatePostingsFormat = delegatePostingsFormat; | ||
| this.bucket = bucket; | ||
| } | ||
|
|
||
| // Needed for SPI | ||
| public CriteriaBasedPostingsFormat() { | ||
| this(null, null); | ||
| } | ||
|
|
||
| @Override | ||
| public FieldsConsumer fieldsConsumer(SegmentWriteState state) throws IOException { | ||
| if (delegatePostingsFormat == null) { | ||
| throw new UnsupportedOperationException( | ||
| "Error - " + getClass().getName() + " has been constructed without a choice of PostingsFormat" | ||
| ); | ||
| } | ||
|
|
||
| FieldsConsumer fieldsConsumer = delegatePostingsFormat.fieldsConsumer(state); | ||
| return new CriteriaBasedFieldsConsumer(fieldsConsumer, state); | ||
| } | ||
|
|
||
| @Override | ||
| public FieldsProducer fieldsProducer(SegmentReadState state) throws IOException { | ||
| assert state.segmentInfo.getAttribute(DELEGATE_CODEC_KEY) != null; | ||
| return PostingsFormat.forName(state.segmentInfo.getAttribute(DELEGATE_CODEC_KEY)).fieldsProducer(state); | ||
| } | ||
|
|
||
| class CriteriaBasedFieldsConsumer extends FieldsConsumer { | ||
| private final FieldsConsumer delegateFieldsConsumer; | ||
| private SegmentWriteState state; | ||
| private boolean closed; | ||
|
|
||
| public CriteriaBasedFieldsConsumer(FieldsConsumer delegateFieldsConsumer, SegmentWriteState state) { | ||
| this.delegateFieldsConsumer = delegateFieldsConsumer; | ||
| this.state = state; | ||
| } | ||
|
|
||
| @Override | ||
| public void write(Fields fields, NormsProducer norms) throws IOException { | ||
| delegateFieldsConsumer.write(fields, norms); | ||
| FieldInfo idFieldInfo = state.fieldInfos.fieldInfo(ATTRIBUTE_BINDING_TARGET_FIELD); | ||
| if (bucket != null) { | ||
| state.segmentInfo.putAttribute(BUCKET_NAME, bucket); | ||
| if (idFieldInfo != null) { | ||
| idFieldInfo.putAttribute(BUCKET_NAME, bucket); | ||
| } | ||
| } else if (state.segmentInfo.getAttribute(BUCKET_NAME) == null) { | ||
| // For segment belonging to parent writer, attributes will be set. In case write went to parent | ||
| // writer (like for no ops writes or for temporary tombstone entry which is added for deletes/updates | ||
| // to sync version across child and parent writers), segments corresponding to those writer does not | ||
| // have | ||
| state.segmentInfo.putAttribute(BUCKET_NAME, PLACEHOLDER_BUCKET_FOR_PARENT_WRITER); | ||
| if (idFieldInfo != null) { | ||
| idFieldInfo.putAttribute(BUCKET_NAME, PLACEHOLDER_BUCKET_FOR_PARENT_WRITER); | ||
| } | ||
| } else if (idFieldInfo != null) { | ||
| idFieldInfo.putAttribute(BUCKET_NAME, state.segmentInfo.getAttribute(BUCKET_NAME)); | ||
| } | ||
|
|
||
| state.segmentInfo.putAttribute(DELEGATE_CODEC_KEY, delegatePostingsFormat.getName()); | ||
| } | ||
|
|
||
| @Override | ||
| public void merge(MergeState mergeState, NormsProducer norms) throws IOException { | ||
| delegateFieldsConsumer.merge(mergeState, norms); | ||
| Set<String> mergeFieldNames = StreamSupport.stream(mergeState.mergeFieldInfos.spliterator(), false) | ||
| .map(FieldInfo::getName) | ||
| .collect(Collectors.toSet()); | ||
| if (mergeFieldNames.contains(ATTRIBUTE_BINDING_TARGET_FIELD) && mergeState.fieldInfos.length > 0) { | ||
| String attribute = mergeState.fieldInfos[0].fieldInfo(ATTRIBUTE_BINDING_TARGET_FIELD).getAttribute(BUCKET_NAME); | ||
| assert attribute != null : "Attribute should not be null during merging segment"; | ||
| mergeState.segmentInfo.putAttribute(BUCKET_NAME, attribute); | ||
|
|
||
| mergeState.mergeFieldInfos.fieldInfo(ATTRIBUTE_BINDING_TARGET_FIELD).putAttribute(BUCKET_NAME, attribute); | ||
| } | ||
|
|
||
| mergeState.segmentInfo.putAttribute(DELEGATE_CODEC_KEY, delegatePostingsFormat.getName()); | ||
| } | ||
|
|
||
| @Override | ||
| public void close() throws IOException { | ||
| if (closed) { | ||
| return; | ||
| } | ||
|
|
||
| closed = true; | ||
| delegateFieldsConsumer.close(); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,3 @@ | ||
| org.opensearch.index.codec.composite.composite912.Composite912Codec | ||
| org.opensearch.index.codec.composite.composite103.Composite103Codec | ||
| org.opensearch.index.codec.composite.backward_codecs.composite101.Composite101Codec | ||
| org.opensearch.index.codec.CriteriaBasedCodec | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this needed to be registered in SPI?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We won't need register name for Codec as SPI will no longer instantiate new Codec as we are passing delegate codec name in parameter. SPI will instantiate only new PostingsFormat: https://github.com/opensearch-project/OpenSearch/pull/20442/changes#diff-577d44ce3ec453c1808090ac68139e531a6d7ba4a0c65350553967c3e159289b |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,3 @@ | ||
| org.apache.lucene.search.suggest.document.Completion50PostingsFormat | ||
| org.opensearch.index.codec.fuzzy.FuzzyFilterPostingsFormat | ||
| org.opensearch.index.codec.CriteriaBasedPostingsFormat |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,134 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /* | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * 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. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package org.opensearch.index.codec; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.apache.lucene.analysis.standard.StandardAnalyzer; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.apache.lucene.codecs.Codec; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.apache.lucene.document.Document; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.apache.lucene.document.Field; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.apache.lucene.document.StringField; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.apache.lucene.document.TextField; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.apache.lucene.index.DirectoryReader; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.apache.lucene.index.IndexReader; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.apache.lucene.index.IndexWriter; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.apache.lucene.index.IndexWriterConfig; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.apache.lucene.index.MultiTerms; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.apache.lucene.index.SegmentCommitInfo; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.apache.lucene.index.SegmentInfos; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.apache.lucene.index.Terms; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.apache.lucene.index.TermsEnum; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.apache.lucene.store.ByteBuffersDirectory; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.apache.lucene.store.Directory; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.apache.lucene.tests.index.BasePostingsFormatTestCase; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.apache.lucene.tests.util.TestUtil; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.apache.lucene.util.BytesRef; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.io.IOException; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public class CriteriaBasedPostingsFormatTests extends BasePostingsFormatTestCase { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private static final String TEST_BUCKET = "test_bucket"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private Codec criteriaBasedPostingFormat = TestUtil.alwaysPostingsFormat( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| new CriteriaBasedPostingsFormat(TestUtil.getDefaultPostingsFormat(), TEST_BUCKET) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public void testBasicFunctionality() throws IOException { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Directory dir = new ByteBuffersDirectory(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IndexWriterConfig iwc = new IndexWriterConfig(new StandardAnalyzer()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| iwc.setCodec(criteriaBasedPostingFormat); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try (IndexWriter writer = new IndexWriter(dir, iwc)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (int i = 0; i < 100; i++) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Document doc = new Document(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| doc.add(new StringField("_id", "doc" + i, Field.Store.YES)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| doc.add(new TextField("field", "value" + i, Field.Store.YES)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| writer.addDocument(doc); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try (IndexReader reader = DirectoryReader.open(dir)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assertEquals(100, reader.numDocs()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Terms terms = MultiTerms.getTerms(reader, "field"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assertNotNull(terms); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| TermsEnum termsEnum = terms.iterator(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| int count = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| BytesRef term; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| while ((term = termsEnum.next()) != null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assertTrue(term.utf8ToString().startsWith("value")); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| count++; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assertEquals(100, count); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+41
to
+69
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: find . -type f -name "CriteriaBasedPostingsFormatTests.java" | head -5Repository: opensearch-project/OpenSearch Length of output: 160 🏁 Script executed: # List test files in the codec directory
fd -t f ".*Tests\.java$" server/src/test/java/org/opensearch/index/codec/Repository: opensearch-project/OpenSearch Length of output: 1725 🏁 Script executed: # Get file size first
wc -l server/src/test/java/org/opensearch/index/codec/CriteriaBasedPostingsFormatTests.javaRepository: opensearch-project/OpenSearch Length of output: 162 🏁 Script executed: cat -n server/src/test/java/org/opensearch/index/codec/CriteriaBasedPostingsFormatTests.javaRepository: opensearch-project/OpenSearch Length of output: 6445 🌐 Web query:
💡 Result: Short answer: ByteBuffersDirectory implements Closeable/AutoCloseable and must be closed to free its heap ByteBuffers — use try-with-resources or call close() when you’re done. [1][2] Key points
Minimal example (conceptual)
Sources 🌐 Web query:
💡 Result: Yes — if you open a DirectoryReader and do not close it (or properly decRef it), you will leak file handles and other resources. Fixes:
Minimal example (concept): References: Close All four test methods create ♻️ Suggested fix (apply to all four test methods)- Directory dir = new ByteBuffersDirectory();
- IndexWriterConfig iwc = new IndexWriterConfig(new StandardAnalyzer());
- iwc.setCodec(criteriaBasedPostingFormat);
-
- try (IndexWriter writer = new IndexWriter(dir, iwc)) {
- for (int i = 0; i < 100; i++) {
- Document doc = new Document();
- doc.add(new StringField("_id", "doc" + i, Field.Store.YES));
- doc.add(new TextField("field", "value" + i, Field.Store.YES));
- writer.addDocument(doc);
- }
- }
-
- try (IndexReader reader = DirectoryReader.open(dir)) {
- assertEquals(100, reader.numDocs());
-
- Terms terms = MultiTerms.getTerms(reader, "field");
- assertNotNull(terms);
- TermsEnum termsEnum = terms.iterator();
-
- int count = 0;
- BytesRef term;
- while ((term = termsEnum.next()) != null) {
- assertTrue(term.utf8ToString().startsWith("value"));
- count++;
- }
- assertEquals(100, count);
- }
+ try (Directory dir = new ByteBuffersDirectory()) {
+ IndexWriterConfig iwc = new IndexWriterConfig(new StandardAnalyzer());
+ iwc.setCodec(criteriaBasedPostingFormat);
+
+ try (IndexWriter writer = new IndexWriter(dir, iwc)) {
+ for (int i = 0; i < 100; i++) {
+ Document doc = new Document();
+ doc.add(new StringField("_id", "doc" + i, Field.Store.YES));
+ doc.add(new TextField("field", "value" + i, Field.Store.YES));
+ writer.addDocument(doc);
+ }
+ }
+
+ try (IndexReader reader = DirectoryReader.open(dir)) {
+ assertEquals(100, reader.numDocs());
+
+ Terms terms = MultiTerms.getTerms(reader, "field");
+ assertNotNull(terms);
+ TermsEnum termsEnum = terms.iterator();
+
+ int count = 0;
+ BytesRef term;
+ while ((term = termsEnum.next()) != null) {
+ assertTrue(term.utf8ToString().startsWith("value"));
+ count++;
+ }
+ assertEquals(100, count);
+ }
+ }📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public void testBucketAttributeIsSetOnSegment() throws IOException { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Directory dir = new ByteBuffersDirectory(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IndexWriterConfig iwc = new IndexWriterConfig(new StandardAnalyzer()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| iwc.setCodec(criteriaBasedPostingFormat); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try (IndexWriter writer = new IndexWriter(dir, iwc)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Document doc = new Document(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| doc.add(new StringField("_id", "doc1", Field.Store.YES)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| doc.add(new TextField("content", "test content", Field.Store.YES)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| writer.addDocument(doc); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SegmentInfos segmentInfos = SegmentInfos.readLatestCommit(dir); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assertFalse("Should have at least one segment", segmentInfos.asList().isEmpty()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (SegmentCommitInfo segmentCommitInfo : segmentInfos) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| String bucketValue = segmentCommitInfo.info.getAttribute(CriteriaBasedPostingsFormat.BUCKET_NAME); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assertEquals("Bucket attribute should be set", TEST_BUCKET, bucketValue); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public void testNullBucketSetsPlaceholder() throws IOException { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Directory dir = new ByteBuffersDirectory(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Codec nullBucketCodec = TestUtil.alwaysPostingsFormat(new CriteriaBasedPostingsFormat(TestUtil.getDefaultPostingsFormat(), null)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IndexWriterConfig iwc = new IndexWriterConfig(new StandardAnalyzer()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| iwc.setCodec(nullBucketCodec); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try (IndexWriter writer = new IndexWriter(dir, iwc)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Document doc = new Document(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| doc.add(new StringField("_id", "doc1", Field.Store.YES)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| doc.add(new TextField("content", "test content", Field.Store.YES)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| writer.addDocument(doc); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SegmentInfos segmentInfos = SegmentInfos.readLatestCommit(dir); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (SegmentCommitInfo segmentCommitInfo : segmentInfos) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| String bucketValue = segmentCommitInfo.info.getAttribute(CriteriaBasedPostingsFormat.BUCKET_NAME); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assertEquals("Placeholder bucket should be set for null bucket", "-2", bucketValue); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public void testEmptyIndex() throws IOException { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Directory dir = new ByteBuffersDirectory(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IndexWriterConfig iwc = new IndexWriterConfig(new StandardAnalyzer()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| iwc.setCodec(criteriaBasedPostingFormat); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try (IndexWriter writer = new IndexWriter(dir, iwc)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Don't add any documents | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try (IndexReader reader = DirectoryReader.open(dir)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assertEquals(0, reader.numDocs()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Terms terms = MultiTerms.getTerms(reader, "_id"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assertNull("Terms should be null for empty index", terms); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Override | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| protected Codec getCodec() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return criteriaBasedPostingFormat; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: opensearch-project/OpenSearch
Length of output: 155
🏁 Script executed:
Repository: opensearch-project/OpenSearch
Length of output: 159
🏁 Script executed:
Repository: opensearch-project/OpenSearch
Length of output: 7396
🏁 Script executed:
Repository: opensearch-project/OpenSearch
Length of output: 1061
🏁 Script executed:
Repository: opensearch-project/OpenSearch
Length of output: 6032
🏁 Script executed:
Repository: opensearch-project/OpenSearch
Length of output: 160
🏁 Script executed:
Repository: opensearch-project/OpenSearch
Length of output: 6445
🏁 Script executed:
Repository: opensearch-project/OpenSearch
Length of output: 4410
🏁 Script executed:
Repository: opensearch-project/OpenSearch
Length of output: 2795
🏁 Script executed:
# Look at CriteriaBasedCodec to understand context cat -n ./server/src/main/java/org/opensearch/index/codec/CriteriaBasedCodec.javaRepository: opensearch-project/OpenSearch
Length of output: 2091
🏁 Script executed:
Repository: opensearch-project/OpenSearch
Length of output: 880
🏁 Script executed:
cat -n ./server/src/main/java/org/opensearch/index/codec/CriteriaBasedDocValuesWriter.java | head -100Repository: opensearch-project/OpenSearch
Length of output: 3146
🏁 Script executed:
sed -n '94,116p' ./server/src/main/java/org/opensearch/index/codec/CriteriaBasedPostingsFormat.javaRepository: opensearch-project/OpenSearch
Length of output: 1514
🏁 Script executed:
Repository: opensearch-project/OpenSearch
Length of output: 55
🏁 Script executed:
Repository: opensearch-project/OpenSearch
Length of output: 55
🏁 Script executed:
Repository: opensearch-project/OpenSearch
Length of output: 243
NPE when the first merged segment lacks
_idfield.Line 125 reads the bucket attribute from
mergeState.fieldInfos[0].fieldInfo(ATTRIBUTE_BINDING_TARGET_FIELD)without null-checking the result. If the first segment is a parent-writer or tombstone segment without the_idfield (as the comments in thewrite()method acknowledge is possible),fieldInfo()returns null, and calling.getAttribute()causes an NPE. This is not protected by the assertion on line 126 since assertions are disabled in production.Scan the merge inputs for the first segment that actually contains the
_idfield rather than assuming the first segment has it.🐛 Proposed fix
📝 Committable suggestion
🤖 Prompt for AI Agents