From a7f42386fed0901f2d7f9ea7698f52528574ce0c Mon Sep 17 00:00:00 2001 From: patsonluk Date: Mon, 17 Jul 2023 17:29:57 -0700 Subject: [PATCH] Merge branch_9x into fs/branch_9x (up to `ccf4b198ec328095d45d2746189dc8ca633e8bcf`) (#20) * Add next minor version 9.7.0 * Fix SynonymQuery equals implementation (#12260) The term member of TermAndBoost used to be a Term instance and became a BytesRef with #11941, which means its equals impl won't take the field name into account. The SynonymQuery equals impl needs to be updated accordingly to take the field into account as well, otherwise synonym queries with same term and boost across different fields are equal which is a bug. * Fix MMapDirectory documentation for Java 20 (#12265) * Don't generate stacktrace in CollectionTerminatedException (#12270) CollectionTerminatedException is always caught and never exposed to users so there's no point in filling in a stack-trace for it. * add missing changelog entry for #12260 * Add missing author to changelog entry for #12220 * Make query timeout members final in ExitableDirectoryReader (#12274) There's a couple of places in the Exitable wrapper classes where queryTimeout is set within the constructor and never modified. This commit makes such members final. * Update javadocs for QueryTimeout (#12272) QueryTimeout was introduced together with ExitableDirectoryReader but is now also optionally set to the IndexSearcher to wrap the bulk scorer with a TimeLimitingBulkScorer. Its javadocs needs updating. * Make TimeExceededException members final (#12271) TimeExceededException has three members that are set within its constructor and never modified. They can be made final. * DOAP changes for release 9.6.0 * Add back-compat indices for 9.6.0 * `ToParentBlockJoinQuery` Explain Support Score Mode (#12245) (#12283) * `ToParentBlockJoinQuery` Explain Support Score Mode --------- Co-authored-by: Marcus * Simplify SliceExecutor and QueueSizeBasedExecutor (#12285) The only behaviour that QueueSizeBasedExecutor overrides from SliceExecutor is when to execute on the caller thread. There is no need to override the whole invokeAll method for that. Instead, this commit introduces a shouldExecuteOnCallerThread method that can be overridden. * [Backport] GITHUB-11838 Add api to allow concurrent query rewrite (#12197) * GITHUB-11838 Change API to allow concurrent query rewrite (#11840) Replace Query#rewrite(IndexReader) with Query#rewrite(IndexSearcher) Co-authored-by: Patrick Zhai Co-authored-by: Adrien Grand Backport of https://github.com/apache/lucene/pull/11840 Changes from original: - Query keeps `rewrite(IndexReader)`, but it is now deprecated - VirtualMethod is used to correct delegate to the overridden methods - The changes to `RewriteMethod` type classes are reverted, this increased the backwards compatibility impact. ------------------------------ ### Description Issue: #11838 #### Updated Proposal * Change signature of rewrite to `rewrite(IndexSearcher)` * How did I migrate the usage: * Use Intellij to do preliminary refactoring for me * For test usage, use searcher whenever is available, otherwise create one using `newSearcher(reader)` * For very few non-test classes which doesn't have IndexSearcher available but called rewrite, create a searcher using `new IndexSearcher(reader)`, tried my best to avoid creating it recurrently (Especially in `FieldQuery`) * For queries who have implemented the rewrite and uses some part of reader's functionality, use shortcut method when possible, otherwise pull out the reader from indexSearcher. * Backport: Concurrent rewrite for KnnVectorQuery (#12160) (#12288) * Concurrent rewrite for KnnVectorQuery (#12160) - Reduce overhead of non-concurrent search by preserving original execution - Improve readability by factoring into separate functions --------- Co-authored-by: Kaival Parikh * adjusting for backport --------- Co-authored-by: Kaival Parikh <46070017+kaivalnp@users.noreply.github.com> Co-authored-by: Kaival Parikh * toposort use iterator to avoid stackoverflow (#12286) Co-authored-by: tangdonghai # Conflicts: # lucene/CHANGES.txt * Fix test to compile with Java 11 after backport of #12286 * Update Javadoc for topoSortStates method after #12286 (#12292) * Optimize HNSW diversity calculation (#12235) * Minor cleanup and improvements to DaciukMihovAutomatonBuilder (#12305) * GITHUB-12291: Skip blank lines from stopwords list. (#12299) * Wrap Query rewrite backwards layer with AccessController (#12308) * Make sure APIJAR reproduces with different timezone (unfortunately java encodes the date using local timezone) (#12315) * Add multi-thread searchability to OnHeapHnswGraph (#12257) * Fix backport error * [MINOR] Update javadoc in Query class (#12233) - add a few missing full stops - update wording in the description of Query#equals method * [Backport] Integrate the Incubating Panama Vector API #12311 (#12327) Leverage accelerated vector hardware instructions in Vector Search. Lucene already has a mechanism that enables the use of non-final JDK APIs, currently used for the Previewing Pamana Foreign API. This change expands this mechanism to include the Incubating Pamana Vector API. When the jdk.incubator.vector module is present at run time the Panamaized version of the low-level primitives used by Vector Search is enabled. If not present, the default scalar version of these low-level primitives is used (as it was previously). Currently, we're only targeting support for JDK 20. A subsequent PR should evaluate JDK 21. --------- Co-authored-by: Uwe Schindler Co-authored-by: Robert Muir * Parallelize knn query rewrite across slices rather than segments (#12325) The concurrent query rewrite for knn vectory query introduced with #12160 requests one thread per segment to the executor. To align this with the IndexSearcher parallel behaviour, we should rather parallelize across slices. Also, we can reuse the same slice executor instance that the index searcher already holds, in that way we are using a QueueSizeBasedExecutor when a thread pool executor is provided. * Optimize ConjunctionDISI.createConjunction (#12328) This method is showing up as a little hot when profiling some queries. Almost all the time spent in this method is just burnt on ceremony around stream indirections that don't inline. Moving this to iterators, simplifying the check for same doc id and also saving one iteration (for the min cost) makes this method far cheaper and easier to read. * Update changes to be correct with ARM (it is called NEON there) * GH#12321: Marked DaciukMihovAutomatonBuilder as deprecated (#12332) Preparing to reduce visibility of this class in a future release * add BitSet.clear() (#12268) # Conflicts: # lucene/CHANGES.txt * Clenaup and update changes and synchronize with 9.x * Update TestVectorUtilProviders.java (#12338) * Don't generate stacktrace for TimeExceededException (#12335) The exception is package private and never rethrown, we can avoid generating a stacktrace for it. * Introduced the Word2VecSynonymFilter (#12169) Co-authored-by: Alessandro Benedetti * Word2VecSynonymFilter constructor null check (#12169) * Use thread-safe search version of HnswGraphSearcher (#12246) Addressing comment received in the PR https://github.com/apache/lucene/pull/12246 * Word2VecSynonymProvider to use standard Integer max value for hnsw searches (#12235) We observed this change was not ported previously from main in an old cherry-pick * Fix searchafter high latency when after value is out of range for segment (#12334) * Make memory fence in `ByteBufferGuard` explicit (#12290) * Add "direct to binary" option for DaciukMihovAutomatonBuilder and use it in TermInSetQuery#visit (#12320) * Add updateDocuments API which accept a query (reopen) (#12346) * GITHUB#11350: Handle backward compatibility when merging segments with different FieldInfo This commits restores Lucene 9's ability to handle indices created with Lucene 8 where there are discrepancies in FieldInfos, such as different IndexOptions * [Tessellator] Improve the checks that validate the diagonal between two polygon nodes (#12353) # Conflicts: # lucene/CHANGES.txt * feat: soft delete optimize (#12339) * Better paging when random reads go backwards (#12357) When reading data from outside the buffer, BufferedIndexInput always resets its buffer to start at the new read position. If we are reading backwards (for example, using an OffHeapFSTStore for a terms dictionary) then this can have the effect of re-reading the same data over and over again. This commit changes BufferedIndexInput to use paging when reading backwards, so that if we ask for a byte that is before the current buffer, we read a block of data of bufferSize that ends at the previous buffer start. Fixes #12356 * Work around SecurityManager issues during initialization of vector api (JDK-8309727) (#12362) * Restrict GraphTokenStreamFiniteStrings#articulationPointsRecurse recursion depth (#12249) * Implement MMapDirectory with Java 21 Project Panama Preview API (#12294) Backport incl JDK21 apijar file with java.util.Objects regenerated * remove relic in apijar folder caused by vector additions * Speed up IndexedDISI Sparse #AdvanceExactWithinBlock for tiny step advance (#12324) * Add checks in KNNVectorField / KNNVectorQuery to only allow non-null, non-empty and finite vectors (#12281) --------- Co-authored-by: Uwe Schindler * Implement VectorUtilProvider with Java 21 Project Panama Vector API (#12363) (#12365) This commit enables the Panama Vector API for Java 21. The version of VectorUtilPanamaProvider for Java 21 is identical to that of Java 20. As such, there is no specific 21 version - the Java 20 version will be loaded from the MRJAR. * Add CHANGES.txt for #12334 Honor after value for skipping documents even if queue is not full for PagingFieldCollector (#12368) Signed-off-by: gashutos * Move TermAndBoost back to its original location. (#12366) PR #12169 accidentally moved the `TermAndBoost` class to a different location, which would break custom sub-classes of `QueryBuilder`. This commit moves it back to its original location. * GITHUB-12252: Add function queries for computing similarity scores between knn vectors (#12253) Co-authored-by: Alessandro Benedetti * hunspell (minor): reduce allocations when processing compound rules (#12316) (cherry picked from commit a454388b80e2a92640b79792f2238acd0e7872b9) * hunspell (minor): reduce allocations when reading the dictionary's morphological data (#12323) there can be many entries with morph data, so we'd better avoid compiling and matching regexes and even stream allocation (cherry picked from commit 4bf1b9420990de1453b9b4bb145d7d37dc750f07) * TestHunspell: reduce the flakiness probability (#12351) * TestHunspell: reduce the flakiness probability We need to check how the timeout interacts with custom exception-throwing checkCanceled. The default timeout seems not enough for some CI agents, so let's increase it. Co-authored-by: Dawid Weiss (cherry picked from commit 5b63a1879ddff8f230e0c1a5023243a2f45bf4f8) * This allows VectorUtilProvider tests to be executed although hardware may not fully support vectorization or if C2 is not enabled (#12376) --------- Signed-off-by: gashutos Co-authored-by: Alan Woodward Co-authored-by: Luca Cavanna Co-authored-by: Uwe Schindler Co-authored-by: Armin Braun Co-authored-by: Mikhail Khludnev Co-authored-by: Marcus Co-authored-by: Benjamin Trent Co-authored-by: Kaival Parikh <46070017+kaivalnp@users.noreply.github.com> Co-authored-by: Kaival Parikh Co-authored-by: tang donghai Co-authored-by: Patrick Zhai Co-authored-by: Greg Miller Co-authored-by: Jerry Chin Co-authored-by: Patrick Zhai Co-authored-by: Andrey Bozhko Co-authored-by: Chris Hegarty <62058229+ChrisHegarty@users.noreply.github.com> Co-authored-by: Robert Muir Co-authored-by: Jonathan Ellis Co-authored-by: Daniele Antuzi Co-authored-by: Alessandro Benedetti Co-authored-by: Chaitanya Gohel <104654647+gashutos@users.noreply.github.com> Co-authored-by: Petr Portnov | PROgrm_JARvis Co-authored-by: Tomas Eduardo Fernandez Lobbe Co-authored-by: Ignacio Vera Co-authored-by: fudongying <30896830+fudongyingluck@users.noreply.github.com> Co-authored-by: Chris Fournier Co-authored-by: gf2121 <52390227+gf2121@users.noreply.github.com> Co-authored-by: Adrien Grand Co-authored-by: Elia Porciani Co-authored-by: Peter Gromov --- build.gradle | 6 +- buildSrc/scriptDepVersions.gradle | 2 +- dev-tools/doap/lucene.rdf | 8 +- ...foreign.gradle => extract-jdk-apis.gradle} | 26 +- .../extract-jdk-apis/ExtractJdkApis.java | 197 ++++++ .../panama-foreign/ExtractForeignAPI.java | 132 ---- ...segment-mrjar.gradle => core-mrjar.gradle} | 10 +- gradle/template.gradle.properties | 2 +- gradle/testing/defaults-tests.gradle | 9 +- lucene/CHANGES.txt | 110 +++- .../analysis/tests/TestRandomChains.java | 25 + .../analysis/common/src/java/module-info.java | 2 + .../lucene/analysis/hunspell/Dictionary.java | 34 +- .../lucene/analysis/hunspell/Hunspell.java | 18 +- .../analysis/hunspell/TrigramAutomaton.java | 2 +- .../synonym/word2vec/Dl4jModelReader.java | 126 ++++ .../synonym/word2vec/TermAndBoost.java | 33 + .../synonym/word2vec/Word2VecModel.java | 95 +++ .../word2vec/Word2VecSynonymFilter.java | 110 ++++ .../Word2VecSynonymFilterFactory.java | 101 +++ .../word2vec/Word2VecSynonymProvider.java | 103 +++ .../Word2VecSynonymProviderFactory.java | 63 ++ .../synonym/word2vec/package-info.java | 19 + ....apache.lucene.analysis.TokenFilterFactory | 1 + .../analysis/core/TestFlattenGraphFilter.java | 4 +- .../analysis/hunspell/TestHunspell.java | 4 +- .../synonym/word2vec/TestDl4jModelReader.java | 98 +++ .../word2vec/TestWord2VecSynonymFilter.java | 152 +++++ .../TestWord2VecSynonymFilterFactory.java | 159 +++++ .../word2vec/TestWord2VecSynonymProvider.java | 131 ++++ ...d2vec-corrupted-vector-dimension-model.zip | Bin 0 -> 323 bytes .../synonym/word2vec/word2vec-empty-model.zip | Bin 0 -> 195 bytes .../synonym/word2vec/word2vec-model.zip | Bin 0 -> 439678 bytes .../lucene/analysis/cn/smart/stopwords.txt | 2 - .../backward_codecs/lucene80/IndexedDISI.java | 4 +- .../lucene90/Lucene90HnswGraphBuilder.java | 8 +- .../lucene91/Lucene91HnswGraphBuilder.java | 8 +- .../TestBackwardsCompatibility.java | 7 +- .../lucene/backward_index/index.9.6.0-cfs.zip | Bin 0 -> 17503 bytes .../backward_index/index.9.6.0-nocfs.zip | Bin 0 -> 17498 bytes .../lucene/backward_index/sorted.9.6.0.zip | Bin 0 -> 142393 bytes .../utils/NearestFuzzyQuery.java | 4 +- lucene/core/src/generated/jdk/README.md | 2 +- lucene/core/src/generated/jdk/jdk19.apijar | Bin 0 -> 19164 bytes lucene/core/src/generated/jdk/jdk20.apijar | Bin 0 -> 58749 bytes lucene/core/src/generated/jdk/jdk21.apijar | Bin 0 -> 17245 bytes .../generated/jdk/panama-foreign-jdk19.apijar | Bin 20781 -> 0 bytes .../generated/jdk/panama-foreign-jdk20.apijar | Bin 19487 -> 0 bytes .../lucene/analysis/WordlistLoader.java | 24 +- .../lucene/codecs/lucene90/IndexedDISI.java | 20 +- .../document/BinaryRangeFieldRangeQuery.java | 5 +- .../document/DoubleRangeSlowRangeQuery.java | 6 +- .../apache/lucene/document/FeatureField.java | 9 +- .../apache/lucene/document/FeatureQuery.java | 7 +- .../document/FloatRangeSlowRangeQuery.java | 6 +- .../document/IntRangeSlowRangeQuery.java | 6 +- .../lucene/document/KnnByteVectorField.java | 8 +- .../lucene/document/KnnFloatVectorField.java | 10 +- .../document/LongRangeSlowRangeQuery.java | 6 +- .../SortedNumericDocValuesRangeQuery.java | 5 +- .../SortedNumericDocValuesSetQuery.java | 5 +- .../SortedSetDocValuesRangeQuery.java | 5 +- .../org/apache/lucene/geo/Tessellator.java | 23 +- .../lucene/index/CachingMergeContext.java | 61 ++ .../index/DocumentsWriterDeleteQueue.java | 21 + .../lucene/index/ExitableDirectoryReader.java | 6 +- .../org/apache/lucene/index/FieldInfo.java | 144 +++++ .../org/apache/lucene/index/FieldInfos.java | 62 ++ .../org/apache/lucene/index/IndexWriter.java | 26 +- .../org/apache/lucene/index/QueryTimeout.java | 13 +- .../index/VectorSimilarityFunction.java | 4 +- .../lucene/search/AbstractKnnVectorQuery.java | 92 ++- .../lucene/search/BlendedTermQuery.java | 10 +- .../apache/lucene/search/BooleanQuery.java | 9 +- .../org/apache/lucene/search/BoostQuery.java | 7 +- .../search/CollectionTerminatedException.java | 6 + .../apache/lucene/search/ConjunctionDISI.java | 45 +- .../lucene/search/ConstantScoreQuery.java | 8 +- .../lucene/search/DisjunctionMaxQuery.java | 8 +- .../lucene/search/DoubleValuesSource.java | 3 +- .../lucene/search/FieldExistsQuery.java | 5 +- .../lucene/search/IndexOrDocValuesQuery.java | 7 +- .../apache/lucene/search/IndexSearcher.java | 8 +- ...xSortSortedNumericDocValuesRangeQuery.java | 5 +- .../lucene/search/KnnByteVectorQuery.java | 2 +- .../lucene/search/KnnFloatVectorQuery.java | 4 +- .../lucene/search/MultiPhraseQuery.java | 5 +- .../apache/lucene/search/MultiTermQuery.java | 8 +- .../lucene/search/NGramPhraseQuery.java | 9 +- .../apache/lucene/search/NamedMatches.java | 5 +- .../org/apache/lucene/search/PhraseQuery.java | 5 +- .../java/org/apache/lucene/search/Query.java | 48 +- .../lucene/search/QueueSizeBasedExecutor.java | 27 +- .../apache/lucene/search/ScoringRewrite.java | 3 +- .../apache/lucene/search/SliceExecutor.java | 57 +- .../apache/lucene/search/SynonymQuery.java | 9 +- .../apache/lucene/search/TermInSetQuery.java | 18 +- .../lucene/search/TimeLimitingBulkScorer.java | 6 + .../lucene/search/TimeLimitingCollector.java | 6 +- .../apache/lucene/search/TopTermsRewrite.java | 3 +- .../search/comparators/NumericComparator.java | 26 +- .../apache/lucene/search/package-info.java | 10 +- .../lucene/store/BufferedIndexInput.java | 61 +- .../apache/lucene/store/ByteBufferGuard.java | 12 +- .../apache/lucene/store/MMapDirectory.java | 20 +- .../java/org/apache/lucene/util/BitSet.java | 10 + .../org/apache/lucene/util/FixedBitSet.java | 5 + .../apache/lucene/util/SparseFixedBitSet.java | 12 + .../org/apache/lucene/util/TermAndVector.java | 72 +++ .../org/apache/lucene/util/UnicodeUtil.java | 83 ++- .../org/apache/lucene/util/VectorUtil.java | 179 ++---- .../util/VectorUtilDefaultProvider.java | 178 ++++++ .../lucene/util/VectorUtilProvider.java | 146 +++++ .../java/org/apache/lucene/util/Version.java | 11 +- .../org/apache/lucene/util/VirtualMethod.java | 13 +- .../lucene/util/automaton/Automata.java | 51 +- .../DaciukMihovAutomatonBuilder.java | 198 +++--- .../lucene/util/automaton/Operations.java | 79 ++- .../graph/GraphTokenStreamFiniteStrings.java | 9 +- .../lucene/util/hnsw/HnswGraphBuilder.java | 133 +++- .../lucene/util/hnsw/HnswGraphSearcher.java | 147 ++++- .../lucene/util/hnsw/NeighborArray.java | 93 ++- .../lucene/util/hnsw/OnHeapHnswGraph.java | 12 +- .../lucene/util/VectorUtilPanamaProvider.java | 499 +++++++++++++++ .../lucene/store/MemorySegmentIndexInput.java | 588 ++++++++++++++++++ .../MemorySegmentIndexInputProvider.java | 120 ++++ .../lucene/util/VectorUtilPanamaProvider.txt | 2 + .../analysis/TestAutomatonToTokenStream.java | 8 +- .../lucene/analysis/TestWordlistLoader.java | 2 +- .../apache/lucene/geo/TestTessellator.java | 22 + .../lucene/index/TestCachingMergeContext.java | 69 ++ .../index/TestExitableDirectoryReader.java | 13 +- .../apache/lucene/index/TestFieldInfo.java | 316 ++++++++++ .../apache/lucene/index/TestFieldInfos.java | 39 ++ .../apache/lucene/index/TestIndexWriter.java | 7 +- .../org/apache/lucene/index/TestKnnGraph.java | 11 +- .../search/BaseKnnVectorQueryTestCase.java | 17 +- .../lucene/search/TestBooleanRewrites.java | 4 +- .../lucene/search/TestFieldExistsQuery.java | 18 +- .../lucene/search/TestIndexSearcher.java | 13 +- ...xSortSortedNumericDocValuesRangeQuery.java | 4 +- .../search/TestKnnFloatVectorQuery.java | 4 +- .../lucene/search/TestMatchNoDocsQuery.java | 4 +- .../lucene/search/TestMatchesIterator.java | 2 +- .../lucene/search/TestNGramPhraseQuery.java | 10 +- .../apache/lucene/search/TestNeedsScores.java | 6 +- .../apache/lucene/search/TestPhraseQuery.java | 2 +- ...estQueryRewriteBackwardsCompatibility.java | 269 ++++++++ .../lucene/search/TestSynonymQuery.java | 18 + .../apache/lucene/search/TestWANDScorer.java | 6 +- .../lucene/store/TestBufferedIndexInput.java | 75 ++- .../lucene/store/TestMmapDirectory.java | 4 +- .../apache/lucene/util/TestUnicodeUtil.java | 22 + .../lucene/util/TestVectorUtilProviders.java | 83 +++ .../util/automaton/TestCompiledAutomaton.java | 2 +- .../TestDaciukMihovAutomatonBuilder.java | 167 ++++- .../lucene/util/automaton/TestOperations.java | 98 ++- .../TestGraphTokenStreamFiniteStrings.java | 24 + .../lucene/util/hnsw/HnswGraphTestCase.java | 116 ++++ .../lucene/util/hnsw/TestNeighborArray.java | 118 +++- .../lucene/distribution/TestModularLayer.java | 2 +- .../apache/lucene/facet/DrillDownQuery.java | 8 +- .../lucene/facet/DrillSidewaysQuery.java | 11 +- .../lucene/facet/range/DoubleRange.java | 13 +- .../apache/lucene/facet/range/LongRange.java | 13 +- .../range/OverlappingLongRangeCounter.java | 4 +- .../lucene/facet/TestDrillDownQuery.java | 3 +- .../lucene/facet/TestDrillSideways.java | 2 +- .../facet/range/TestRangeFacetCounts.java | 6 +- .../highlight/WeightedSpanTermExtractor.java | 2 +- .../uhighlight/MemoryIndexOffsetStrategy.java | 4 +- .../search/uhighlight/UnifiedHighlighter.java | 10 +- .../search/vectorhighlight/FieldQuery.java | 37 +- .../search/highlight/TestHighlighter.java | 4 +- .../custom/TestHighlightCustomQuery.java | 4 +- .../uhighlight/TestUnifiedHighlighter.java | 9 +- .../uhighlight/TestUnifiedHighlighterMTQ.java | 4 +- .../TestUnifiedHighlighterStrictPhrases.java | 4 +- .../vectorhighlight/AbstractTestCase.java | 8 +- .../vectorhighlight/TestFieldQuery.java | 12 +- .../join/ParentChildrenBlockJoinQuery.java | 7 +- .../search/join/ToChildBlockJoinQuery.java | 7 +- .../search/join/ToParentBlockJoinQuery.java | 49 +- .../lucene/search/join/TestBlockJoin.java | 5 +- .../lucene/luke/models/search/SearchImpl.java | 2 +- .../TestDiversifiedTopDocsCollector.java | 6 +- .../monitor/ForceNoBulkScoringQuery.java | 7 +- .../lucene/monitor/MonitorTestBase.java | 4 +- .../monitor/TestForceNoBulkScoringQuery.java | 2 +- .../lucene/queries/CommonTermsQuery.java | 4 +- .../queries/function/FunctionScoreQuery.java | 5 +- .../queries/function/FunctionValues.java | 8 + .../valuesource/ByteKnnVectorFieldSource.java | 84 +++ .../ByteVectorSimilarityFunction.java | 49 ++ .../ConstKnnByteVectorValueSource.java | 73 +++ .../valuesource/ConstKnnFloatValueSource.java | 74 +++ .../FloatKnnVectorFieldSource.java | 83 +++ .../FloatVectorSimilarityFunction.java | 48 ++ .../valuesource/VectorFieldFunction.java | 56 ++ .../valuesource/VectorSimilarityFunction.java | 96 +++ .../lucene/queries/mlt/MoreLikeThisQuery.java | 6 +- .../queries/payloads/PayloadScoreQuery.java | 7 +- .../payloads/SpanPayloadCheckQuery.java | 7 +- .../queries/spans/FieldMaskingSpanQuery.java | 7 +- .../queries/spans/SpanContainQuery.java | 9 +- .../spans/SpanMultiTermQueryWrapper.java | 4 +- .../lucene/queries/spans/SpanNearQuery.java | 7 +- .../lucene/queries/spans/SpanNotQuery.java | 9 +- .../lucene/queries/spans/SpanOrQuery.java | 7 +- .../queries/spans/SpanPositionCheckQuery.java | 7 +- .../TestKnnVectorSimilarityFunctions.java | 260 ++++++++ .../queries/function/TestValueSources.java | 4 +- .../queries/spans/AssertingSpanQuery.java | 7 +- .../spans/TestFieldMaskingSpanQuery.java | 2 +- .../ComplexPhraseQueryParser.java | 5 +- .../surround/query/DistanceRewriteQuery.java | 6 +- .../surround/query/RewriteQuery.java | 4 +- .../query/SimpleTermRewriteQuery.java | 6 +- .../queryparser/xml/TestCoreParser.java | 2 +- .../sandbox/queries/FuzzyLikeThisQuery.java | 4 +- .../sandbox/search/CombinedFieldQuery.java | 2 +- .../lucene/sandbox/search/CoveringQuery.java | 9 +- .../sandbox/search/MultiRangeQuery.java | 3 +- .../sandbox/search/PhraseWildcardQuery.java | 4 +- .../sandbox/search/TermAutomatonQuery.java | 3 +- .../queries/TestFuzzyLikeThisQuery.java | 8 +- .../sandbox/search/TestCoveringQuery.java | 3 +- .../sandbox/search/TestMultiRangeQueries.java | 4 +- .../search/TestTermAutomatonQuery.java | 18 +- .../composite/CompositeVerifyQuery.java | 7 +- .../spatial/vector/PointVectorStrategy.java | 5 +- .../suggest/document/CompletionQuery.java | 8 +- .../document/SuggestIndexSearcher.java | 2 +- .../analyzing/TestAnalyzingSuggester.java | 16 - .../analysis/BaseTokenStreamTestCase.java | 149 ++++- .../lucene/tests/index/RandomIndexWriter.java | 8 +- .../lucene/tests/search/AssertingQuery.java | 7 +- .../tests/search/BlockScoreQueryWrapper.java | 7 +- .../search/RandomApproximationQuery.java | 7 +- .../lucene/tests/util/BaseBitSetTestCase.java | 21 + .../tests/geo/github-12352-1.geojson.gz | Bin 0 -> 82183 bytes .../tests/geo/github-12352-2.geojson.gz | Bin 0 -> 111625 bytes 242 files changed, 7342 insertions(+), 1217 deletions(-) rename gradle/generation/{panama-foreign.gradle => extract-jdk-apis.gradle} (73%) create mode 100644 gradle/generation/extract-jdk-apis/ExtractJdkApis.java delete mode 100644 gradle/generation/panama-foreign/ExtractForeignAPI.java rename gradle/java/{memorysegment-mrjar.gradle => core-mrjar.gradle} (82%) create mode 100644 lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/Dl4jModelReader.java create mode 100644 lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/TermAndBoost.java create mode 100644 lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/Word2VecModel.java create mode 100644 lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/Word2VecSynonymFilter.java create mode 100644 lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/Word2VecSynonymFilterFactory.java create mode 100644 lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/Word2VecSynonymProvider.java create mode 100644 lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/Word2VecSynonymProviderFactory.java create mode 100644 lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/package-info.java create mode 100644 lucene/analysis/common/src/test/org/apache/lucene/analysis/synonym/word2vec/TestDl4jModelReader.java create mode 100644 lucene/analysis/common/src/test/org/apache/lucene/analysis/synonym/word2vec/TestWord2VecSynonymFilter.java create mode 100644 lucene/analysis/common/src/test/org/apache/lucene/analysis/synonym/word2vec/TestWord2VecSynonymFilterFactory.java create mode 100644 lucene/analysis/common/src/test/org/apache/lucene/analysis/synonym/word2vec/TestWord2VecSynonymProvider.java create mode 100644 lucene/analysis/common/src/test/org/apache/lucene/analysis/synonym/word2vec/word2vec-corrupted-vector-dimension-model.zip create mode 100644 lucene/analysis/common/src/test/org/apache/lucene/analysis/synonym/word2vec/word2vec-empty-model.zip create mode 100644 lucene/analysis/common/src/test/org/apache/lucene/analysis/synonym/word2vec/word2vec-model.zip create mode 100644 lucene/backward-codecs/src/test/org/apache/lucene/backward_index/index.9.6.0-cfs.zip create mode 100644 lucene/backward-codecs/src/test/org/apache/lucene/backward_index/index.9.6.0-nocfs.zip create mode 100644 lucene/backward-codecs/src/test/org/apache/lucene/backward_index/sorted.9.6.0.zip create mode 100644 lucene/core/src/generated/jdk/jdk19.apijar create mode 100644 lucene/core/src/generated/jdk/jdk20.apijar create mode 100644 lucene/core/src/generated/jdk/jdk21.apijar delete mode 100644 lucene/core/src/generated/jdk/panama-foreign-jdk19.apijar delete mode 100644 lucene/core/src/generated/jdk/panama-foreign-jdk20.apijar create mode 100644 lucene/core/src/java/org/apache/lucene/index/CachingMergeContext.java create mode 100644 lucene/core/src/java/org/apache/lucene/util/TermAndVector.java create mode 100644 lucene/core/src/java/org/apache/lucene/util/VectorUtilDefaultProvider.java create mode 100644 lucene/core/src/java/org/apache/lucene/util/VectorUtilProvider.java create mode 100644 lucene/core/src/java20/org/apache/lucene/util/VectorUtilPanamaProvider.java create mode 100644 lucene/core/src/java21/org/apache/lucene/store/MemorySegmentIndexInput.java create mode 100644 lucene/core/src/java21/org/apache/lucene/store/MemorySegmentIndexInputProvider.java create mode 100644 lucene/core/src/java21/org/apache/lucene/util/VectorUtilPanamaProvider.txt create mode 100644 lucene/core/src/test/org/apache/lucene/index/TestCachingMergeContext.java create mode 100644 lucene/core/src/test/org/apache/lucene/index/TestFieldInfo.java create mode 100644 lucene/core/src/test/org/apache/lucene/search/TestQueryRewriteBackwardsCompatibility.java create mode 100644 lucene/core/src/test/org/apache/lucene/util/TestVectorUtilProviders.java create mode 100644 lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/ByteKnnVectorFieldSource.java create mode 100644 lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/ByteVectorSimilarityFunction.java create mode 100644 lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/ConstKnnByteVectorValueSource.java create mode 100644 lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/ConstKnnFloatValueSource.java create mode 100644 lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/FloatKnnVectorFieldSource.java create mode 100644 lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/FloatVectorSimilarityFunction.java create mode 100644 lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/VectorFieldFunction.java create mode 100644 lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/VectorSimilarityFunction.java create mode 100644 lucene/queries/src/test/org/apache/lucene/queries/function/TestKnnVectorSimilarityFunctions.java create mode 100644 lucene/test-framework/src/resources/org/apache/lucene/tests/geo/github-12352-1.geojson.gz create mode 100644 lucene/test-framework/src/resources/org/apache/lucene/tests/geo/github-12352-2.geojson.gz diff --git a/build.gradle b/build.gradle index ba77f2ef6d5c..0eae57bd10f3 100644 --- a/build.gradle +++ b/build.gradle @@ -36,7 +36,7 @@ apply from: file('gradle/globals.gradle') // Calculate project version: version = { // Release manager: update base version here after release: - String baseVersion = '9.6.0' + String baseVersion = '9.7.0' // On a release explicitly set release version in one go: // -Dversion.release=x.y.z @@ -119,7 +119,7 @@ apply from: file('gradle/ide/eclipse.gradle') // (java, tests) apply from: file('gradle/java/folder-layout.gradle') apply from: file('gradle/java/javac.gradle') -apply from: file('gradle/java/memorysegment-mrjar.gradle') +apply from: file('gradle/java/core-mrjar.gradle') apply from: file('gradle/testing/defaults-tests.gradle') apply from: file('gradle/testing/randomization.gradle') apply from: file('gradle/testing/fail-on-no-tests.gradle') @@ -158,7 +158,7 @@ apply from: file('gradle/generation/javacc.gradle') apply from: file('gradle/generation/forUtil.gradle') apply from: file('gradle/generation/antlr.gradle') apply from: file('gradle/generation/unicode-test-classes.gradle') -apply from: file('gradle/generation/panama-foreign.gradle') +apply from: file('gradle/generation/extract-jdk-apis.gradle') apply from: file('gradle/datasets/external-datasets.gradle') diff --git a/buildSrc/scriptDepVersions.gradle b/buildSrc/scriptDepVersions.gradle index 8751da632492..a6eae860b1c0 100644 --- a/buildSrc/scriptDepVersions.gradle +++ b/buildSrc/scriptDepVersions.gradle @@ -22,7 +22,7 @@ ext { scriptDepVersions = [ "apache-rat": "0.14", - "asm": "9.4", + "asm": "9.5", "commons-codec": "1.13", "ecj": "3.30.0", "flexmark": "0.61.24", diff --git a/dev-tools/doap/lucene.rdf b/dev-tools/doap/lucene.rdf index 0c749ad54d44..c0a09528cef2 100644 --- a/dev-tools/doap/lucene.rdf +++ b/dev-tools/doap/lucene.rdf @@ -67,6 +67,13 @@ + + + lucene-9.6.0 + 2023-05-09 + 9.6.0 + + lucene-9.5.0 @@ -74,7 +81,6 @@ 9.5.0 - lucene-9.4.2 diff --git a/gradle/generation/panama-foreign.gradle b/gradle/generation/extract-jdk-apis.gradle similarity index 73% rename from gradle/generation/panama-foreign.gradle rename to gradle/generation/extract-jdk-apis.gradle index 694c4656e2f6..78e74aa261a3 100644 --- a/gradle/generation/panama-foreign.gradle +++ b/gradle/generation/extract-jdk-apis.gradle @@ -17,10 +17,17 @@ def resources = scriptResources(buildscript) +configure(rootProject) { + ext { + // also change this in extractor tool: ExtractForeignAPI + vectorIncubatorJavaVersions = [ JavaVersion.VERSION_20, JavaVersion.VERSION_21 ] as Set + } +} + configure(project(":lucene:core")) { ext { apijars = file('src/generated/jdk'); - panamaJavaVersions = [ 19, 20 ] + mrjarJavaVersions = [ 19, 20, 21 ] } configurations { @@ -31,9 +38,9 @@ configure(project(":lucene:core")) { apiextractor "org.ow2.asm:asm:${scriptDepVersions['asm']}" } - for (jdkVersion : panamaJavaVersions) { - def task = tasks.create(name: "generatePanamaForeignApiJar${jdkVersion}", type: JavaExec) { - description "Regenerate the API-only JAR file with public Panama Foreign API from JDK ${jdkVersion}" + for (jdkVersion : mrjarJavaVersions) { + def task = tasks.create(name: "generateJdkApiJar${jdkVersion}", type: JavaExec) { + description "Regenerate the API-only JAR file with public Panama Foreign & Vector API from JDK ${jdkVersion}" group "generation" javaLauncher = javaToolchains.launcherFor { @@ -45,18 +52,21 @@ configure(project(":lucene:core")) { javaLauncher.get() return true } catch (Exception e) { - logger.warn('Launcher for Java {} is not available; skipping regeneration of Panama Foreign API JAR.', jdkVersion) + logger.warn('Launcher for Java {} is not available; skipping regeneration of Panama Foreign & Vector API JAR.', jdkVersion) logger.warn('Error: {}', e.cause?.message) logger.warn("Please make sure to point env 'JAVA{}_HOME' to exactly JDK version {} or enable Gradle toolchain auto-download.", jdkVersion, jdkVersion) return false } } - + classpath = configurations.apiextractor - mainClass = file("${resources}/ExtractForeignAPI.java") as String + mainClass = file("${resources}/ExtractJdkApis.java") as String + systemProperties = [ + 'user.timezone': 'UTC' + ] args = [ jdkVersion, - new File(apijars, "panama-foreign-jdk${jdkVersion}.apijar"), + new File(apijars, "jdk${jdkVersion}.apijar"), ] } diff --git a/gradle/generation/extract-jdk-apis/ExtractJdkApis.java b/gradle/generation/extract-jdk-apis/ExtractJdkApis.java new file mode 100644 index 000000000000..7dfb9edfe2a0 --- /dev/null +++ b/gradle/generation/extract-jdk-apis/ExtractJdkApis.java @@ -0,0 +1,197 @@ +/* + * 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. + */ +import java.io.IOException; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.PathMatcher; +import java.nio.file.Paths; +import java.nio.file.attribute.FileTime; +import java.time.Instant; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.TreeMap; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; + +public final class ExtractJdkApis { + + private static final FileTime FIXED_FILEDATE = FileTime.from(Instant.parse("2022-01-01T00:00:00Z")); + + private static final String PATTERN_PANAMA_FOREIGN = "java.base/java/{lang/foreign/*,nio/channels/FileChannel,util/Objects}"; + private static final String PATTERN_VECTOR_INCUBATOR = "jdk.incubator.vector/jdk/incubator/vector/*"; + private static final String PATTERN_VECTOR_VM_INTERNALS = "java.base/jdk/internal/vm/vector/VectorSupport{,$Vector,$VectorMask,$VectorPayload,$VectorShuffle}"; + + static final Map> CLASSFILE_PATTERNS = Map.of( + 19, List.of(PATTERN_PANAMA_FOREIGN), + 20, List.of(PATTERN_PANAMA_FOREIGN, PATTERN_VECTOR_VM_INTERNALS, PATTERN_VECTOR_INCUBATOR), + 21, List.of(PATTERN_PANAMA_FOREIGN) + ); + + public static void main(String... args) throws IOException { + if (args.length != 2) { + throw new IllegalArgumentException("Need two parameters: java version, output file"); + } + Integer jdk = Integer.valueOf(args[0]); + if (jdk.intValue() != Runtime.version().feature()) { + throw new IllegalStateException("Incorrect java version: " + Runtime.version().feature()); + } + if (!CLASSFILE_PATTERNS.containsKey(jdk)) { + throw new IllegalArgumentException("No support to extract stubs from java version: " + jdk); + } + var outputPath = Paths.get(args[1]); + + // create JRT filesystem and build a combined FileMatcher: + var jrtPath = Paths.get(URI.create("jrt:/")).toRealPath(); + var patterns = CLASSFILE_PATTERNS.get(jdk).stream() + .map(pattern -> jrtPath.getFileSystem().getPathMatcher("glob:" + pattern + ".class")) + .toArray(PathMatcher[]::new); + PathMatcher pattern = p -> Arrays.stream(patterns).anyMatch(matcher -> matcher.matches(p)); + + // Collect all files to process: + final List filesToExtract; + try (var stream = Files.walk(jrtPath)) { + filesToExtract = stream.filter(p -> pattern.matches(jrtPath.relativize(p))).collect(Collectors.toList()); + } + + // Process all class files: + try (var out = new ZipOutputStream(Files.newOutputStream(outputPath))) { + process(filesToExtract, out); + } + } + + private static void process(List filesToExtract, ZipOutputStream out) throws IOException { + var classesToInclude = new HashSet(); + var references = new HashMap(); + var processed = new TreeMap(); + System.out.println("Transforming " + filesToExtract.size() + " class files..."); + for (Path p : filesToExtract) { + try (var in = Files.newInputStream(p)) { + var reader = new ClassReader(in); + var cw = new ClassWriter(0); + var cleaner = new Cleaner(cw, classesToInclude, references); + reader.accept(cleaner, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); + processed.put(reader.getClassName(), cw.toByteArray()); + } + } + // recursively add all superclasses / interfaces of visible classes to classesToInclude: + for (Set a = classesToInclude; !a.isEmpty();) { + a = a.stream().map(references::get).filter(Objects::nonNull).flatMap(Arrays::stream).collect(Collectors.toSet()); + classesToInclude.addAll(a); + } + // remove all non-visible or not referenced classes: + processed.keySet().removeIf(Predicate.not(classesToInclude::contains)); + System.out.println("Writing " + processed.size() + " visible classes..."); + for (var cls : processed.entrySet()) { + String cn = cls.getKey(); + System.out.println("Writing stub for class: " + cn); + out.putNextEntry(new ZipEntry(cn.concat(".class")).setLastModifiedTime(FIXED_FILEDATE)); + out.write(cls.getValue()); + out.closeEntry(); + } + classesToInclude.removeIf(processed.keySet()::contains); + System.out.println("Referenced classes not included: " + classesToInclude); + } + + static boolean isVisible(int access) { + return (access & (Opcodes.ACC_PROTECTED | Opcodes.ACC_PUBLIC)) != 0; + } + + static class Cleaner extends ClassVisitor { + private static final String PREVIEW_ANN = "jdk/internal/javac/PreviewFeature"; + private static final String PREVIEW_ANN_DESCR = Type.getObjectType(PREVIEW_ANN).getDescriptor(); + + private final Set classesToInclude; + private final Map references; + + Cleaner(ClassWriter out, Set classesToInclude, Map references) { + super(Opcodes.ASM9, out); + this.classesToInclude = classesToInclude; + this.references = references; + } + + @Override + public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { + super.visit(Opcodes.V11, access, name, signature, superName, interfaces); + if (isVisible(access)) { + classesToInclude.add(name); + } + references.put(name, Stream.concat(Stream.of(superName), Arrays.stream(interfaces)).toArray(String[]::new)); + } + + @Override + public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) { + return Objects.equals(descriptor, PREVIEW_ANN_DESCR) ? null : super.visitAnnotation(descriptor, visible); + } + + @Override + public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) { + if (!isVisible(access)) { + return null; + } + return new FieldVisitor(Opcodes.ASM9, super.visitField(access, name, descriptor, signature, value)) { + @Override + public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) { + return Objects.equals(descriptor, PREVIEW_ANN_DESCR) ? null : super.visitAnnotation(descriptor, visible); + } + }; + } + + @Override + public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { + if (!isVisible(access)) { + return null; + } + return new MethodVisitor(Opcodes.ASM9, super.visitMethod(access, name, descriptor, signature, exceptions)) { + @Override + public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) { + return Objects.equals(descriptor, PREVIEW_ANN_DESCR) ? null : super.visitAnnotation(descriptor, visible); + } + }; + } + + @Override + public void visitInnerClass(String name, String outerName, String innerName, int access) { + if (!Objects.equals(outerName, PREVIEW_ANN)) { + super.visitInnerClass(name, outerName, innerName, access); + } + } + + @Override + public void visitPermittedSubclass​(String c) { + } + + } + +} diff --git a/gradle/generation/panama-foreign/ExtractForeignAPI.java b/gradle/generation/panama-foreign/ExtractForeignAPI.java deleted file mode 100644 index 44253ea0122b..000000000000 --- a/gradle/generation/panama-foreign/ExtractForeignAPI.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * 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. - */ -import java.io.IOException; -import java.net.URI; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.attribute.FileTime; -import java.time.Instant; -import java.util.Objects; -import java.util.stream.Collectors; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; - -import org.objectweb.asm.AnnotationVisitor; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.FieldVisitor; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; - -public final class ExtractForeignAPI { - - private static final FileTime FIXED_FILEDATE = FileTime.from(Instant.parse("2022-01-01T00:00:00Z")); - - public static void main(String... args) throws IOException { - if (args.length != 2) { - throw new IllegalArgumentException("Need two parameters: java version, output file"); - } - if (Integer.parseInt(args[0]) != Runtime.version().feature()) { - throw new IllegalStateException("Incorrect java version: " + Runtime.version().feature()); - } - var outputPath = Paths.get(args[1]); - var javaBaseModule = Paths.get(URI.create("jrt:/")).resolve("java.base").toRealPath(); - var fileMatcher = javaBaseModule.getFileSystem().getPathMatcher("glob:java/{lang/foreign/*,nio/channels/FileChannel,util/Objects}.class"); - try (var out = new ZipOutputStream(Files.newOutputStream(outputPath)); var stream = Files.walk(javaBaseModule)) { - var filesToExtract = stream.map(javaBaseModule::relativize).filter(fileMatcher::matches).sorted().collect(Collectors.toList()); - for (Path relative : filesToExtract) { - System.out.println("Processing class file: " + relative); - try (var in = Files.newInputStream(javaBaseModule.resolve(relative))) { - final var reader = new ClassReader(in); - final var cw = new ClassWriter(0); - reader.accept(new Cleaner(cw), ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); - out.putNextEntry(new ZipEntry(relative.toString()).setLastModifiedTime(FIXED_FILEDATE)); - out.write(cw.toByteArray()); - out.closeEntry(); - } - } - } - } - - static class Cleaner extends ClassVisitor { - private static final String PREVIEW_ANN = "jdk/internal/javac/PreviewFeature"; - private static final String PREVIEW_ANN_DESCR = Type.getObjectType(PREVIEW_ANN).getDescriptor(); - - private boolean completelyHidden = false; - - Cleaner(ClassWriter out) { - super(Opcodes.ASM9, out); - } - - private boolean isHidden(int access) { - return completelyHidden || (access & (Opcodes.ACC_PROTECTED | Opcodes.ACC_PUBLIC)) == 0; - } - - @Override - public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { - super.visit(Opcodes.V11, access, name, signature, superName, interfaces); - completelyHidden = isHidden(access); - } - - @Override - public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) { - return Objects.equals(descriptor, PREVIEW_ANN_DESCR) ? null : super.visitAnnotation(descriptor, visible); - } - - @Override - public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) { - if (isHidden(access)) { - return null; - } - return new FieldVisitor(Opcodes.ASM9, super.visitField(access, name, descriptor, signature, value)) { - @Override - public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) { - return Objects.equals(descriptor, PREVIEW_ANN_DESCR) ? null : super.visitAnnotation(descriptor, visible); - } - }; - } - - @Override - public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { - if (isHidden(access)) { - return null; - } - return new MethodVisitor(Opcodes.ASM9, super.visitMethod(access, name, descriptor, signature, exceptions)) { - @Override - public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) { - return Objects.equals(descriptor, PREVIEW_ANN_DESCR) ? null : super.visitAnnotation(descriptor, visible); - } - }; - } - - @Override - public void visitInnerClass(String name, String outerName, String innerName, int access) { - if (!Objects.equals(outerName, PREVIEW_ANN)) { - super.visitInnerClass(name, outerName, innerName, access); - } - } - - @Override - public void visitPermittedSubclass​(String c) { - } - - } - -} diff --git a/gradle/java/memorysegment-mrjar.gradle b/gradle/java/core-mrjar.gradle similarity index 82% rename from gradle/java/memorysegment-mrjar.gradle rename to gradle/java/core-mrjar.gradle index 137f8a3c567d..5715e782f000 100644 --- a/gradle/java/memorysegment-mrjar.gradle +++ b/gradle/java/core-mrjar.gradle @@ -15,11 +15,11 @@ * limitations under the License. */ -// Produce an MR-JAR with Java 19+ MemorySegment implementation for MMapDirectory +// Produce an MR-JAR with Java 19+ foreign and vector implementations configure(project(":lucene:core")) { plugins.withType(JavaPlugin) { - for (jdkVersion : panamaJavaVersions) { + for (jdkVersion : mrjarJavaVersions) { sourceSets.create("main${jdkVersion}") { java { srcDirs = ["src/java${jdkVersion}"] @@ -29,7 +29,7 @@ configure(project(":lucene:core")) { dependencies.add("main${jdkVersion}Implementation", sourceSets.main.output) tasks.named("compileMain${jdkVersion}Java").configure { - def apijar = new File(apijars, "panama-foreign-jdk${jdkVersion}.apijar") + def apijar = new File(apijars, "jdk${jdkVersion}.apijar") inputs.file(apijar) @@ -40,12 +40,14 @@ configure(project(":lucene:core")) { "-Xlint:-options", "--patch-module", "java.base=${apijar}", "--add-exports", "java.base/java.lang.foreign=ALL-UNNAMED", + // for compilation we patch the incubator packages into java.base, this has no effect on resulting class files: + "--add-exports", "java.base/jdk.incubator.vector=ALL-UNNAMED", ] } } tasks.named('jar').configure { - for (jdkVersion : panamaJavaVersions) { + for (jdkVersion : mrjarJavaVersions) { into("META-INF/versions/${jdkVersion}") { from sourceSets["main${jdkVersion}"].output } diff --git a/gradle/template.gradle.properties b/gradle/template.gradle.properties index a626d39f3bb5..9ac8c42e9dd4 100644 --- a/gradle/template.gradle.properties +++ b/gradle/template.gradle.properties @@ -102,5 +102,5 @@ tests.jvms=@TEST_JVMS@ org.gradle.java.installations.auto-download=true # Set these to enable automatic JVM location discovery. -org.gradle.java.installations.fromEnv=JAVA17_HOME,JAVA19_HOME,JAVA20_HOME,JAVA21_HOME,RUNTIME_JAVA_HOME +org.gradle.java.installations.fromEnv=JAVA17_HOME,JAVA19_HOME,JAVA20_HOME,JAVA21_HOME,JAVA22_HOME,RUNTIME_JAVA_HOME #org.gradle.java.installations.paths=(custom paths) diff --git a/gradle/testing/defaults-tests.gradle b/gradle/testing/defaults-tests.gradle index 9f50cda8ca79..f7a348f0b66c 100644 --- a/gradle/testing/defaults-tests.gradle +++ b/gradle/testing/defaults-tests.gradle @@ -47,7 +47,7 @@ allprojects { description: "Number of forked test JVMs"], [propName: 'tests.haltonfailure', value: true, description: "Halt processing on test failure."], [propName: 'tests.jvmargs', - value: { -> propertyOrEnvOrDefault("tests.jvmargs", "TEST_JVM_ARGS", "-XX:TieredStopAtLevel=1 -XX:+UseParallelGC -XX:ActiveProcessorCount=1") }, + value: { -> propertyOrEnvOrDefault("tests.jvmargs", "TEST_JVM_ARGS", isCIBuild ? "" : "-XX:TieredStopAtLevel=1 -XX:+UseParallelGC -XX:ActiveProcessorCount=1") }, description: "Arguments passed to each forked JVM."], // Other settings. [propName: 'tests.neverUpToDate', value: true, @@ -119,11 +119,16 @@ allprojects { if (rootProject.runtimeJavaVersion < JavaVersion.VERSION_16) { jvmArgs '--illegal-access=deny' } - + // Lucene needs to optional modules at runtime, which we want to enforce for testing // (if the runner JVM does not support them, it will fail tests): jvmArgs '--add-modules', 'jdk.unsupported,jdk.management' + // Enable the vector incubator module on supported Java versions: + if (rootProject.vectorIncubatorJavaVersions.contains(rootProject.runtimeJavaVersion)) { + jvmArgs '--add-modules', 'jdk.incubator.vector' + } + def loggingConfigFile = layout.projectDirectory.file("${resources}/logging.properties") def tempDir = layout.projectDirectory.dir(testsTmpDir.toString()) jvmArgumentProviders.add( diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index 322e8c2acae8..341101cf2a95 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -3,6 +3,106 @@ Lucene Change Log For more information on past and future Lucene versions, please see: http://s.apache.org/luceneversions +======================== Lucene 9.7.0 ======================= + +API Changes +--------------------- + +* GITHUB#11840, GITHUB#12304: Query rewrite now takes an IndexSearcher instead of + IndexReader to enable concurrent rewriting. Please note: This is implemented in + a backwards compatible way. A query overriding any of both rewrite methods is + supported. To implement this backwards layer in Lucene 9.x the + RuntimePermission "accessDeclaredMembers" is needed in applications using + SecurityManager. (Patrick Zhai, Ben Trent, Uwe Schindler) + +* GITHUB#12321: DaciukMihovAutomatonBuilder has been marked deprecated in preparation of reducing its visibility in + a future release. (Greg Miller) + +* GITHUB#12268: Add BitSet.clear() without parameters for clearing the entire set + (Jonathan Ellis) + +* GITHUB#12346: add new IndexWriter#updateDocuments(Query, Iterable) API + to update documents atomically, with respect to refresh and commit using a query. (Patrick Zhai) + +New Features +--------------------- + +* GITHUB#12257: Create OnHeapHnswGraphSearcher to let OnHeapHnswGraph to be searched in a thread-safety manner. (Patrick Zhai) + +* GITHUB#12302, GITHUB#12311, GITHUB#12363: Add vectorized implementations of VectorUtil.dotProduct(), + squareDistance(), cosine() with Java 20 or 21 jdk.incubator.vector APIs. Applications started + with command line parameter "java --add-modules jdk.incubator.vector" on exactly Java 20 or 21 + will automatically use the new vectorized implementations if running on a supported platform + (x86 AVX2 or later, ARM NEON). This is an opt-in feature and requires explicit Java + command line flag! When enabled, Lucene logs a notice using java.util.logging. Please test + thoroughly and report bugs/slowness to Lucene's mailing list. + (Chris Hegarty, Robert Muir, Uwe Schindler) + +* GITHUB#12294: Add support for Java 21 foreign memory API. If Java 19 up to 21 is used, + MMapDirectory will mmap Lucene indexes in chunks of 16 GiB (instead of 1 GiB) and indexes + closed while queries are running can no longer crash the JVM. To disable this feature, + pass the following sysprop on Java command line: + "-Dorg.apache.lucene.store.MMapDirectory.enableMemorySegments=false" (Uwe Schindler) + +* GITHUB#12252 Add function queries for computing similarity scores between knn vectors. (Elia Porciani, Alessandro Benedetti) + +Improvements +--------------------- + +* GITHUB#12245: Add support for Score Mode to `ToParentBlockJoinQuery` explain. (Marcus Eagan via Mikhail Khludnev) + +* GITHUB#12305: Minor cleanup and improvements to DaciukMihovAutomatonBuilder. (Greg Miller) + +* GITHUB#12325: Parallelize AbstractKnnVectorQuery rewrite across slices rather than segments. (Luca Cavanna) + +* GITHUB#12333: NumericLeafComparator#competitiveIterator makes better use of a "search after" value when paginating. + (Chaitanya Gohel) + +* GITHUB#12290: Make memory fence in ByteBufferGuard explicit using `VarHandle.fullFence()` + +* GITHUB#12320: Add "direct to binary" option for DaciukMihovAutomatonBuilder and use it in TermInSetQuery#visit. + (Greg Miller) + +* GITHUB#12281: Require indexed KNN float vectors and query vectors to be finite. (Jonathan Ellis, Uwe Schindler) + +Optimizations +--------------------- + +* GITHUB#12324: Speed up sparse block advanceExact with tiny step in IndexedDISI. (Guo Feng) + +* GITHUB#12270 Don't generate stacktrace in CollectionTerminatedException. (Armin Braun) + +* GITHUB#12160: Concurrent rewrite for AbstractKnnVectorQuery. (Kaival Parikh) + +* GITHUB#12286 Toposort use iterator to avoid stackoverflow. (Tang Donghai) + +* GITHUB#12235: Optimize HNSW diversity calculation. (Patrick Zhai) + +* GITHUB#12328: Optimize ConjunctionDISI.createConjunction (Armin Braun) + +* GITHUB#12357: Better paging when doing backwards random reads. This speeds up + queries relying on terms in NIOFSDirectory and SimpleFSDirectory. (Alan Woodward) + +* GITHUB#12339: Optimize part of duplicate calculation numDeletesToMerge in merge phase (fudongying) + +* GITHUB#12334: Honor after value for skipping documents even if queue is not full for PagingFieldCollector (Chaitanya Gohel) + +Bug Fixes +--------------------- + +* GITHUB#12291: Skip blank lines from stopwords list. (Jerry Chin) + +* GITHUB#11350: Handle possible differences in FieldInfo when merging indices created with Lucene 8.x (Tomás Fernández Löbbe) + +* GITHUB#12352: [Tessellator] Improve the checks that validate the diagonal between two polygon nodes so + the resulting polygons are valid counter clockwise polygons. (Ignacio Vera) + +* LUCENE-10181: Restrict GraphTokenStreamFiniteStrings#articulationPointsRecurse recursion depth. (Chris Fournier) + +Other +--------------------- +(No changes) + ======================== Lucene 9.6.0 ======================= API Changes @@ -32,6 +132,8 @@ New Features crash the JVM. To disable this feature, pass the following sysprop on Java command line: "-Dorg.apache.lucene.store.MMapDirectory.enableMemorySegments=false" (Uwe Schindler) +* GITHUB#12169: Introduce a new token filter to expand synonyms based on Word2Vec DL4j models. (Daniele Antuzi, Ilaria Petreti, Alessandro Benedetti) + Improvements --------------------- @@ -45,6 +147,8 @@ Improvements * GITHUB#12175: Remove SortedSetDocValuesSetQuery in favor of TermInSetQuery with DocValuesRewriteMethod. (Greg Miller) +* GITHUB#12166: Remove the now unused class pointInPolygon. (Marcus Eagan via Christine Poerschke and Nick Knize) + * GITHUB#12126: Refactor part of IndexFileDeleter and ReplicaFileDeleter into a public common utility class FileDeleter. (Patrick Zhai) @@ -86,7 +190,9 @@ Bug Fixes * GITHUB#12212: Bug fix for a DrillSideways issue where matching hits could occasionally be missed. (Frederic Thevenet) -* GITHUB#12220: Hunspell: disallow hidden title-case entries from compound middle/end +* GITHUB#12220: Hunspell: disallow hidden title-case entries from compound middle/end (Peter Gromov) + +* GITHUB#12260: Fix SynonymQuery equals implementation to take the targeted field name into account (Luca Cavanna) Build --------------------- @@ -157,7 +263,7 @@ API Changes * GITHUB#11962: VectorValues#cost() now delegates to VectorValues#size(). (Adrien Grand) - + * GITHUB#11984: Improved TimeLimitBulkScorer to check the timeout at exponantial rate. (Costin Leau) diff --git a/lucene/analysis.tests/src/test/org/apache/lucene/analysis/tests/TestRandomChains.java b/lucene/analysis.tests/src/test/org/apache/lucene/analysis/tests/TestRandomChains.java index 8c245e7058c7..988deaf99e59 100644 --- a/lucene/analysis.tests/src/test/org/apache/lucene/analysis/tests/TestRandomChains.java +++ b/lucene/analysis.tests/src/test/org/apache/lucene/analysis/tests/TestRandomChains.java @@ -89,6 +89,8 @@ import org.apache.lucene.analysis.standard.StandardTokenizer; import org.apache.lucene.analysis.stempel.StempelStemmer; import org.apache.lucene.analysis.synonym.SynonymMap; +import org.apache.lucene.analysis.synonym.word2vec.Word2VecModel; +import org.apache.lucene.analysis.synonym.word2vec.Word2VecSynonymProvider; import org.apache.lucene.store.ByteBuffersDirectory; import org.apache.lucene.tests.analysis.BaseTokenStreamTestCase; import org.apache.lucene.tests.analysis.MockTokenFilter; @@ -99,8 +101,10 @@ import org.apache.lucene.tests.util.automaton.AutomatonTestUtil; import org.apache.lucene.util.AttributeFactory; import org.apache.lucene.util.AttributeSource; +import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.CharsRef; import org.apache.lucene.util.IgnoreRandomChains; +import org.apache.lucene.util.TermAndVector; import org.apache.lucene.util.Version; import org.apache.lucene.util.automaton.Automaton; import org.apache.lucene.util.automaton.CharacterRunAutomaton; @@ -415,6 +419,27 @@ private String randomNonEmptyString(Random random) { } } }); + put( + Word2VecSynonymProvider.class, + random -> { + final int numEntries = atLeast(10); + final int vectorDimension = random.nextInt(99) + 1; + Word2VecModel model = new Word2VecModel(numEntries, vectorDimension); + for (int j = 0; j < numEntries; j++) { + String s = TestUtil.randomSimpleString(random, 10, 20); + float[] vec = new float[vectorDimension]; + for (int i = 0; i < vectorDimension; i++) { + vec[i] = random.nextFloat(); + } + model.addTermAndVector(new TermAndVector(new BytesRef(s), vec)); + } + try { + return new Word2VecSynonymProvider(model); + } catch (IOException e) { + Rethrow.rethrow(e); + return null; // unreachable code + } + }); put( DateFormat.class, random -> { diff --git a/lucene/analysis/common/src/java/module-info.java b/lucene/analysis/common/src/java/module-info.java index 5679f0dde295..15ad5a2b1af0 100644 --- a/lucene/analysis/common/src/java/module-info.java +++ b/lucene/analysis/common/src/java/module-info.java @@ -78,6 +78,7 @@ exports org.apache.lucene.analysis.sr; exports org.apache.lucene.analysis.sv; exports org.apache.lucene.analysis.synonym; + exports org.apache.lucene.analysis.synonym.word2vec; exports org.apache.lucene.analysis.ta; exports org.apache.lucene.analysis.te; exports org.apache.lucene.analysis.th; @@ -256,6 +257,7 @@ org.apache.lucene.analysis.sv.SwedishMinimalStemFilterFactory, org.apache.lucene.analysis.synonym.SynonymFilterFactory, org.apache.lucene.analysis.synonym.SynonymGraphFilterFactory, + org.apache.lucene.analysis.synonym.word2vec.Word2VecSynonymFilterFactory, org.apache.lucene.analysis.core.FlattenGraphFilterFactory, org.apache.lucene.analysis.te.TeluguNormalizationFilterFactory, org.apache.lucene.analysis.te.TeluguStemFilterFactory, diff --git a/lucene/analysis/common/src/java/org/apache/lucene/analysis/hunspell/Dictionary.java b/lucene/analysis/common/src/java/org/apache/lucene/analysis/hunspell/Dictionary.java index e94047b67db3..b7a4029a523b 100644 --- a/lucene/analysis/common/src/java/org/apache/lucene/analysis/hunspell/Dictionary.java +++ b/lucene/analysis/common/src/java/org/apache/lucene/analysis/hunspell/Dictionary.java @@ -155,7 +155,7 @@ public class Dictionary { boolean checkCompoundCase, checkCompoundDup, checkCompoundRep; boolean checkCompoundTriple, simplifiedTriple; int compoundMin = 3, compoundMax = Integer.MAX_VALUE; - List compoundRules; // nullable + CompoundRule[] compoundRules; // nullable List checkCompoundPatterns = new ArrayList<>(); // ignored characters (dictionary, affix, inputs) @@ -601,11 +601,11 @@ private String[] splitBySpace(LineNumberReader reader, String line, int minParts return parts; } - private List parseCompoundRules(LineNumberReader reader, int num) + private CompoundRule[] parseCompoundRules(LineNumberReader reader, int num) throws IOException, ParseException { - List compoundRules = new ArrayList<>(); + CompoundRule[] compoundRules = new CompoundRule[num]; for (int i = 0; i < num; i++) { - compoundRules.add(new CompoundRule(singleArgument(reader, reader.readLine()), this)); + compoundRules[i] = new CompoundRule(singleArgument(reader, reader.readLine()), this); } return compoundRules; } @@ -992,7 +992,7 @@ private int mergeDictionaries( // if we haven't seen any custom morphological data, try to parse one if (!hasCustomMorphData) { int morphStart = line.indexOf(MORPH_SEPARATOR); - if (morphStart >= 0 && morphStart < line.length()) { + if (morphStart >= 0) { String data = line.substring(morphStart + 1); hasCustomMorphData = splitMorphData(data).stream().anyMatch(s -> !s.startsWith("ph:")); @@ -1321,14 +1321,22 @@ private List splitMorphData(String morphData) { if (morphData.isBlank()) { return Collections.emptyList(); } - return Arrays.stream(morphData.split("\\s+")) - .filter( - s -> - s.length() > 3 - && Character.isLetter(s.charAt(0)) - && Character.isLetter(s.charAt(1)) - && s.charAt(2) == ':') - .collect(Collectors.toList()); + + List result = null; + int start = 0; + for (int i = 0; i <= morphData.length(); i++) { + if (i == morphData.length() || Character.isWhitespace(morphData.charAt(i))) { + if (i - start > 3 + && Character.isLetter(morphData.charAt(start)) + && Character.isLetter(morphData.charAt(start + 1)) + && morphData.charAt(start + 2) == ':') { + if (result == null) result = new ArrayList<>(); + result.add(morphData.substring(start, i)); + } + start = i + 1; + } + } + return result == null ? List.of() : result; } boolean hasFlag(IntsRef forms, char flag) { diff --git a/lucene/analysis/common/src/java/org/apache/lucene/analysis/hunspell/Hunspell.java b/lucene/analysis/common/src/java/org/apache/lucene/analysis/hunspell/Hunspell.java index 1e2a1add13cd..3b58e0f4f980 100644 --- a/lucene/analysis/common/src/java/org/apache/lucene/analysis/hunspell/Hunspell.java +++ b/lucene/analysis/common/src/java/org/apache/lucene/analysis/hunspell/Hunspell.java @@ -450,7 +450,7 @@ private boolean checkCompoundRules( if (forms != null) { words.add(forms); - if (dictionary.compoundRules.stream().anyMatch(r -> r.mayMatch(words))) { + if (mayHaveCompoundRule(words)) { if (checkLastCompoundPart(wordChars, offset + breakPos, length - breakPos, words)) { return true; } @@ -467,6 +467,15 @@ private boolean checkCompoundRules( return false; } + private boolean mayHaveCompoundRule(List words) { + for (CompoundRule rule : dictionary.compoundRules) { + if (rule.mayMatch(words)) { + return true; + } + } + return false; + } + private boolean checkLastCompoundPart( char[] wordChars, int start, int length, List words) { IntsRef ref = new IntsRef(new int[1], 0, 1); @@ -475,7 +484,12 @@ private boolean checkLastCompoundPart( Stemmer.RootProcessor stopOnMatching = (stem, formID, morphDataId, outerPrefix, innerPrefix, outerSuffix, innerSuffix) -> { ref.ints[0] = formID; - return dictionary.compoundRules.stream().noneMatch(r -> r.fullyMatches(words)); + for (CompoundRule r : dictionary.compoundRules) { + if (r.fullyMatches(words)) { + return false; + } + } + return true; }; boolean found = !stemmer.doStem(wordChars, start, length, COMPOUND_RULE_END, stopOnMatching); words.remove(words.size() - 1); diff --git a/lucene/analysis/common/src/java/org/apache/lucene/analysis/hunspell/TrigramAutomaton.java b/lucene/analysis/common/src/java/org/apache/lucene/analysis/hunspell/TrigramAutomaton.java index dfe994ccf827..f4404e4bcf02 100644 --- a/lucene/analysis/common/src/java/org/apache/lucene/analysis/hunspell/TrigramAutomaton.java +++ b/lucene/analysis/common/src/java/org/apache/lucene/analysis/hunspell/TrigramAutomaton.java @@ -79,7 +79,7 @@ private int runAutomatonOnStringChars(String s) { } int ngramScore(CharsRef s2) { - countedSubstrings.clear(0, countedSubstrings.length()); + countedSubstrings.clear(); int score1 = 0, score2 = 0, score3 = 0; // scores for substrings of length 1, 2 and 3 diff --git a/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/Dl4jModelReader.java b/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/Dl4jModelReader.java new file mode 100644 index 000000000000..f022dd8eca67 --- /dev/null +++ b/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/Dl4jModelReader.java @@ -0,0 +1,126 @@ +/* + * 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.analysis.synonym.word2vec; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.Locale; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import org.apache.lucene.util.BytesRef; +import org.apache.lucene.util.TermAndVector; + +/** + * Dl4jModelReader reads the file generated by the library Deeplearning4j and provide a + * Word2VecModel with normalized vectors + * + *

Dl4j Word2Vec documentation: + * https://deeplearning4j.konduit.ai/v/en-1.0.0-beta7/language-processing/word2vec Example to + * generate a model using dl4j: + * https://github.com/eclipse/deeplearning4j-examples/blob/master/dl4j-examples/src/main/java/org/deeplearning4j/examples/advanced/modelling/embeddingsfromcorpus/word2vec/Word2VecRawTextExample.java + * + * @lucene.experimental + */ +public class Dl4jModelReader implements Closeable { + + private static final String MODEL_FILE_NAME_PREFIX = "syn0"; + + private final ZipInputStream word2VecModelZipFile; + + public Dl4jModelReader(InputStream stream) { + this.word2VecModelZipFile = new ZipInputStream(new BufferedInputStream(stream)); + } + + public Word2VecModel read() throws IOException { + + ZipEntry entry; + while ((entry = word2VecModelZipFile.getNextEntry()) != null) { + String fileName = entry.getName(); + if (fileName.startsWith(MODEL_FILE_NAME_PREFIX)) { + BufferedReader reader = + new BufferedReader(new InputStreamReader(word2VecModelZipFile, StandardCharsets.UTF_8)); + + String header = reader.readLine(); + String[] headerValues = header.split(" "); + int dictionarySize = Integer.parseInt(headerValues[0]); + int vectorDimension = Integer.parseInt(headerValues[1]); + + Word2VecModel model = new Word2VecModel(dictionarySize, vectorDimension); + String line = reader.readLine(); + boolean isTermB64Encoded = false; + if (line != null) { + String[] tokens = line.split(" "); + isTermB64Encoded = + tokens[0].substring(0, 3).toLowerCase(Locale.ROOT).compareTo("b64") == 0; + model.addTermAndVector(extractTermAndVector(tokens, vectorDimension, isTermB64Encoded)); + } + while ((line = reader.readLine()) != null) { + String[] tokens = line.split(" "); + model.addTermAndVector(extractTermAndVector(tokens, vectorDimension, isTermB64Encoded)); + } + return model; + } + } + throw new IllegalArgumentException( + "Cannot read Dl4j word2vec model - '" + + MODEL_FILE_NAME_PREFIX + + "' file is missing in the zip. '" + + MODEL_FILE_NAME_PREFIX + + "' is a mandatory file containing the mapping between terms and vectors generated by the DL4j library."); + } + + private static TermAndVector extractTermAndVector( + String[] tokens, int vectorDimension, boolean isTermB64Encoded) { + BytesRef term = isTermB64Encoded ? decodeB64Term(tokens[0]) : new BytesRef((tokens[0])); + + float[] vector = new float[tokens.length - 1]; + + if (vectorDimension != vector.length) { + throw new RuntimeException( + String.format( + Locale.ROOT, + "Word2Vec model file corrupted. " + + "Declared vectors of size %d but found vector of size %d for word %s (%s)", + vectorDimension, + vector.length, + tokens[0], + term.utf8ToString())); + } + + for (int i = 1; i < tokens.length; i++) { + vector[i - 1] = Float.parseFloat(tokens[i]); + } + return new TermAndVector(term, vector); + } + + static BytesRef decodeB64Term(String term) { + byte[] buffer = Base64.getDecoder().decode(term.substring(4)); + return new BytesRef(buffer, 0, buffer.length); + } + + @Override + public void close() throws IOException { + word2VecModelZipFile.close(); + } +} diff --git a/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/TermAndBoost.java b/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/TermAndBoost.java new file mode 100644 index 000000000000..03fdeecb0f20 --- /dev/null +++ b/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/TermAndBoost.java @@ -0,0 +1,33 @@ +/* + * 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.analysis.synonym.word2vec; + +import org.apache.lucene.util.BytesRef; + +/** Wraps a term and boost */ +public class TermAndBoost { + /** the term */ + public final BytesRef term; + /** the boost */ + public final float boost; + + /** Creates a new TermAndBoost */ + public TermAndBoost(BytesRef term, float boost) { + this.term = BytesRef.deepCopyOf(term); + this.boost = boost; + } +} diff --git a/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/Word2VecModel.java b/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/Word2VecModel.java new file mode 100644 index 000000000000..6719639b67d9 --- /dev/null +++ b/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/Word2VecModel.java @@ -0,0 +1,95 @@ +/* + * 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.analysis.synonym.word2vec; + +import java.io.IOException; +import org.apache.lucene.util.BytesRef; +import org.apache.lucene.util.BytesRefHash; +import org.apache.lucene.util.TermAndVector; +import org.apache.lucene.util.hnsw.RandomAccessVectorValues; + +/** + * Word2VecModel is a class representing the parsed Word2Vec model containing the vectors for each + * word in dictionary + * + * @lucene.experimental + */ +public class Word2VecModel implements RandomAccessVectorValues { + + private final int dictionarySize; + private final int vectorDimension; + private final TermAndVector[] termsAndVectors; + private final BytesRefHash word2Vec; + private int loadedCount = 0; + + public Word2VecModel(int dictionarySize, int vectorDimension) { + this.dictionarySize = dictionarySize; + this.vectorDimension = vectorDimension; + this.termsAndVectors = new TermAndVector[dictionarySize]; + this.word2Vec = new BytesRefHash(); + } + + private Word2VecModel( + int dictionarySize, + int vectorDimension, + TermAndVector[] termsAndVectors, + BytesRefHash word2Vec) { + this.dictionarySize = dictionarySize; + this.vectorDimension = vectorDimension; + this.termsAndVectors = termsAndVectors; + this.word2Vec = word2Vec; + } + + public void addTermAndVector(TermAndVector modelEntry) { + modelEntry.normalizeVector(); + this.termsAndVectors[loadedCount++] = modelEntry; + this.word2Vec.add(modelEntry.getTerm()); + } + + @Override + public float[] vectorValue(int targetOrd) { + return termsAndVectors[targetOrd].getVector(); + } + + public float[] vectorValue(BytesRef term) { + int termOrd = this.word2Vec.find(term); + if (termOrd < 0) return null; + TermAndVector entry = this.termsAndVectors[termOrd]; + return (entry == null) ? null : entry.getVector(); + } + + public BytesRef termValue(int targetOrd) { + return termsAndVectors[targetOrd].getTerm(); + } + + @Override + public int dimension() { + return vectorDimension; + } + + @Override + public int size() { + return dictionarySize; + } + + @Override + public RandomAccessVectorValues copy() throws IOException { + return new Word2VecModel( + this.dictionarySize, this.vectorDimension, this.termsAndVectors, this.word2Vec); + } +} diff --git a/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/Word2VecSynonymFilter.java b/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/Word2VecSynonymFilter.java new file mode 100644 index 000000000000..a8db4c4c764a --- /dev/null +++ b/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/Word2VecSynonymFilter.java @@ -0,0 +1,110 @@ +/* + * 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.analysis.synonym.word2vec; + +import java.io.IOException; +import java.util.LinkedList; +import java.util.List; +import org.apache.lucene.analysis.TokenFilter; +import org.apache.lucene.analysis.TokenStream; +import org.apache.lucene.analysis.synonym.SynonymGraphFilter; +import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; +import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute; +import org.apache.lucene.analysis.tokenattributes.PositionLengthAttribute; +import org.apache.lucene.analysis.tokenattributes.TypeAttribute; +import org.apache.lucene.util.BytesRef; +import org.apache.lucene.util.BytesRefBuilder; + +/** + * Applies single-token synonyms from a Word2Vec trained network to an incoming {@link TokenStream}. + * + * @lucene.experimental + */ +public final class Word2VecSynonymFilter extends TokenFilter { + + private final CharTermAttribute termAtt = addAttribute(CharTermAttribute.class); + private final PositionIncrementAttribute posIncrementAtt = + addAttribute(PositionIncrementAttribute.class); + private final PositionLengthAttribute posLenAtt = addAttribute(PositionLengthAttribute.class); + private final TypeAttribute typeAtt = addAttribute(TypeAttribute.class); + + private final Word2VecSynonymProvider synonymProvider; + private final int maxSynonymsPerTerm; + private final float minAcceptedSimilarity; + private final LinkedList synonymBuffer = new LinkedList<>(); + private State lastState; + + /** + * Apply previously built synonymProvider to incoming tokens. + * + * @param input input tokenstream + * @param synonymProvider synonym provider + * @param maxSynonymsPerTerm maximum number of result returned by the synonym search + * @param minAcceptedSimilarity minimal value of cosine similarity between the searched vector and + * the retrieved ones + */ + public Word2VecSynonymFilter( + TokenStream input, + Word2VecSynonymProvider synonymProvider, + int maxSynonymsPerTerm, + float minAcceptedSimilarity) { + super(input); + if (synonymProvider == null) { + throw new IllegalArgumentException("The SynonymProvider must be non-null"); + } + this.synonymProvider = synonymProvider; + this.maxSynonymsPerTerm = maxSynonymsPerTerm; + this.minAcceptedSimilarity = minAcceptedSimilarity; + } + + @Override + public boolean incrementToken() throws IOException { + + if (!synonymBuffer.isEmpty()) { + TermAndBoost synonym = synonymBuffer.pollFirst(); + clearAttributes(); + restoreState(this.lastState); + termAtt.setEmpty(); + termAtt.append(synonym.term.utf8ToString()); + typeAtt.setType(SynonymGraphFilter.TYPE_SYNONYM); + posLenAtt.setPositionLength(1); + posIncrementAtt.setPositionIncrement(0); + return true; + } + + if (input.incrementToken()) { + BytesRefBuilder bytesRefBuilder = new BytesRefBuilder(); + bytesRefBuilder.copyChars(termAtt.buffer(), 0, termAtt.length()); + BytesRef term = bytesRefBuilder.get(); + List synonyms = + this.synonymProvider.getSynonyms(term, maxSynonymsPerTerm, minAcceptedSimilarity); + if (synonyms.size() > 0) { + this.lastState = captureState(); + this.synonymBuffer.addAll(synonyms); + } + return true; + } + return false; + } + + @Override + public void reset() throws IOException { + super.reset(); + synonymBuffer.clear(); + } +} diff --git a/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/Word2VecSynonymFilterFactory.java b/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/Word2VecSynonymFilterFactory.java new file mode 100644 index 000000000000..32b6288926fc --- /dev/null +++ b/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/Word2VecSynonymFilterFactory.java @@ -0,0 +1,101 @@ +/* + * 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.analysis.synonym.word2vec; + +import java.io.IOException; +import java.util.Locale; +import java.util.Map; +import org.apache.lucene.analysis.TokenFilterFactory; +import org.apache.lucene.analysis.TokenStream; +import org.apache.lucene.analysis.synonym.word2vec.Word2VecSynonymProviderFactory.Word2VecSupportedFormats; +import org.apache.lucene.util.ResourceLoader; +import org.apache.lucene.util.ResourceLoaderAware; + +/** + * Factory for {@link Word2VecSynonymFilter}. + * + * @lucene.experimental + * @lucene.spi {@value #NAME} + */ +public class Word2VecSynonymFilterFactory extends TokenFilterFactory + implements ResourceLoaderAware { + + /** SPI name */ + public static final String NAME = "Word2VecSynonym"; + + public static final int DEFAULT_MAX_SYNONYMS_PER_TERM = 5; + public static final float DEFAULT_MIN_ACCEPTED_SIMILARITY = 0.8f; + + private final int maxSynonymsPerTerm; + private final float minAcceptedSimilarity; + private final Word2VecSupportedFormats format; + private final String word2vecModelFileName; + + private Word2VecSynonymProvider synonymProvider; + + public Word2VecSynonymFilterFactory(Map args) { + super(args); + this.maxSynonymsPerTerm = getInt(args, "maxSynonymsPerTerm", DEFAULT_MAX_SYNONYMS_PER_TERM); + this.minAcceptedSimilarity = + getFloat(args, "minAcceptedSimilarity", DEFAULT_MIN_ACCEPTED_SIMILARITY); + this.word2vecModelFileName = require(args, "model"); + + String modelFormat = get(args, "format", "dl4j").toUpperCase(Locale.ROOT); + try { + this.format = Word2VecSupportedFormats.valueOf(modelFormat); + } catch (IllegalArgumentException exc) { + throw new IllegalArgumentException("Model format '" + modelFormat + "' not supported", exc); + } + + if (!args.isEmpty()) { + throw new IllegalArgumentException("Unknown parameters: " + args); + } + if (minAcceptedSimilarity <= 0 || minAcceptedSimilarity > 1) { + throw new IllegalArgumentException( + "minAcceptedSimilarity must be in the range (0, 1]. Found: " + minAcceptedSimilarity); + } + if (maxSynonymsPerTerm <= 0) { + throw new IllegalArgumentException( + "maxSynonymsPerTerm must be a positive integer greater than 0. Found: " + + maxSynonymsPerTerm); + } + } + + /** Default ctor for compatibility with SPI */ + public Word2VecSynonymFilterFactory() { + throw defaultCtorException(); + } + + Word2VecSynonymProvider getSynonymProvider() { + return this.synonymProvider; + } + + @Override + public TokenStream create(TokenStream input) { + return synonymProvider == null + ? input + : new Word2VecSynonymFilter( + input, synonymProvider, maxSynonymsPerTerm, minAcceptedSimilarity); + } + + @Override + public void inform(ResourceLoader loader) throws IOException { + this.synonymProvider = + Word2VecSynonymProviderFactory.getSynonymProvider(loader, word2vecModelFileName, format); + } +} diff --git a/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/Word2VecSynonymProvider.java b/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/Word2VecSynonymProvider.java new file mode 100644 index 000000000000..3089f1587a4e --- /dev/null +++ b/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/Word2VecSynonymProvider.java @@ -0,0 +1,103 @@ +/* + * 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.analysis.synonym.word2vec; + +import static org.apache.lucene.util.hnsw.HnswGraphBuilder.DEFAULT_BEAM_WIDTH; +import static org.apache.lucene.util.hnsw.HnswGraphBuilder.DEFAULT_MAX_CONN; + +import java.io.IOException; +import java.util.LinkedList; +import java.util.List; +import org.apache.lucene.index.VectorEncoding; +import org.apache.lucene.index.VectorSimilarityFunction; +import org.apache.lucene.util.BytesRef; +import org.apache.lucene.util.hnsw.HnswGraphBuilder; +import org.apache.lucene.util.hnsw.HnswGraphSearcher; +import org.apache.lucene.util.hnsw.NeighborQueue; +import org.apache.lucene.util.hnsw.OnHeapHnswGraph; + +/** + * The Word2VecSynonymProvider generates the list of sysnonyms of a term. + * + * @lucene.experimental + */ +public class Word2VecSynonymProvider { + + private static final VectorSimilarityFunction SIMILARITY_FUNCTION = + VectorSimilarityFunction.DOT_PRODUCT; + private static final VectorEncoding VECTOR_ENCODING = VectorEncoding.FLOAT32; + private final Word2VecModel word2VecModel; + private final OnHeapHnswGraph hnswGraph; + + /** + * Word2VecSynonymProvider constructor + * + * @param model containing the set of TermAndVector entries + */ + public Word2VecSynonymProvider(Word2VecModel model) throws IOException { + word2VecModel = model; + + HnswGraphBuilder builder = + HnswGraphBuilder.create( + word2VecModel, + VECTOR_ENCODING, + SIMILARITY_FUNCTION, + DEFAULT_MAX_CONN, + DEFAULT_BEAM_WIDTH, + HnswGraphBuilder.randSeed); + this.hnswGraph = builder.build(word2VecModel.copy()); + } + + public List getSynonyms( + BytesRef term, int maxSynonymsPerTerm, float minAcceptedSimilarity) throws IOException { + + if (term == null) { + throw new IllegalArgumentException("Term must not be null"); + } + + LinkedList result = new LinkedList<>(); + float[] query = word2VecModel.vectorValue(term); + if (query != null) { + NeighborQueue synonyms = + HnswGraphSearcher.search( + query, + // The query vector is in the model. When looking for the top-k + // it's always the nearest neighbour of itself so, we look for the top-k+1 + maxSynonymsPerTerm + 1, + word2VecModel, + VECTOR_ENCODING, + SIMILARITY_FUNCTION, + hnswGraph, + null, + Integer.MAX_VALUE); + + int size = synonyms.size(); + for (int i = 0; i < size; i++) { + float similarity = synonyms.topScore(); + int id = synonyms.pop(); + + BytesRef synonym = word2VecModel.termValue(id); + // We remove the original query term + if (!synonym.equals(term) && similarity >= minAcceptedSimilarity) { + result.addFirst(new TermAndBoost(synonym, similarity)); + } + } + } + return result; + } +} diff --git a/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/Word2VecSynonymProviderFactory.java b/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/Word2VecSynonymProviderFactory.java new file mode 100644 index 000000000000..ea849e653cd6 --- /dev/null +++ b/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/Word2VecSynonymProviderFactory.java @@ -0,0 +1,63 @@ +/* + * 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.analysis.synonym.word2vec; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import org.apache.lucene.util.ResourceLoader; + +/** + * Supply Word2Vec Word2VecSynonymProvider cache avoiding that multiple instances of + * Word2VecSynonymFilterFactory will instantiate multiple instances of the same SynonymProvider. + * Assumes synonymProvider implementations are thread-safe. + */ +public class Word2VecSynonymProviderFactory { + + enum Word2VecSupportedFormats { + DL4J + } + + private static Map word2vecSynonymProviders = + new ConcurrentHashMap<>(); + + public static Word2VecSynonymProvider getSynonymProvider( + ResourceLoader loader, String modelFileName, Word2VecSupportedFormats format) + throws IOException { + Word2VecSynonymProvider synonymProvider = word2vecSynonymProviders.get(modelFileName); + if (synonymProvider == null) { + try (InputStream stream = loader.openResource(modelFileName)) { + try (Dl4jModelReader reader = getModelReader(format, stream)) { + synonymProvider = new Word2VecSynonymProvider(reader.read()); + } + } + word2vecSynonymProviders.put(modelFileName, synonymProvider); + } + return synonymProvider; + } + + private static Dl4jModelReader getModelReader( + Word2VecSupportedFormats format, InputStream stream) { + switch (format) { + case DL4J: + return new Dl4jModelReader(stream); + } + return null; + } +} diff --git a/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/package-info.java b/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/package-info.java new file mode 100644 index 000000000000..e8d69ab3cf9b --- /dev/null +++ b/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/package-info.java @@ -0,0 +1,19 @@ +/* + * 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. + */ + +/** Analysis components for Synonyms using Word2Vec model. */ +package org.apache.lucene.analysis.synonym.word2vec; diff --git a/lucene/analysis/common/src/resources/META-INF/services/org.apache.lucene.analysis.TokenFilterFactory b/lucene/analysis/common/src/resources/META-INF/services/org.apache.lucene.analysis.TokenFilterFactory index 19a34b7840a8..1e4e17eaeadf 100644 --- a/lucene/analysis/common/src/resources/META-INF/services/org.apache.lucene.analysis.TokenFilterFactory +++ b/lucene/analysis/common/src/resources/META-INF/services/org.apache.lucene.analysis.TokenFilterFactory @@ -118,6 +118,7 @@ org.apache.lucene.analysis.sv.SwedishLightStemFilterFactory org.apache.lucene.analysis.sv.SwedishMinimalStemFilterFactory org.apache.lucene.analysis.synonym.SynonymFilterFactory org.apache.lucene.analysis.synonym.SynonymGraphFilterFactory +org.apache.lucene.analysis.synonym.word2vec.Word2VecSynonymFilterFactory org.apache.lucene.analysis.core.FlattenGraphFilterFactory org.apache.lucene.analysis.te.TeluguNormalizationFilterFactory org.apache.lucene.analysis.te.TeluguStemFilterFactory diff --git a/lucene/analysis/common/src/test/org/apache/lucene/analysis/core/TestFlattenGraphFilter.java b/lucene/analysis/common/src/test/org/apache/lucene/analysis/core/TestFlattenGraphFilter.java index 7b35f56016cb..7fa901ac5bf4 100644 --- a/lucene/analysis/common/src/test/org/apache/lucene/analysis/core/TestFlattenGraphFilter.java +++ b/lucene/analysis/common/src/test/org/apache/lucene/analysis/core/TestFlattenGraphFilter.java @@ -40,8 +40,8 @@ import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.CharsRef; import org.apache.lucene.util.CharsRefBuilder; +import org.apache.lucene.util.automaton.Automata; import org.apache.lucene.util.automaton.Automaton; -import org.apache.lucene.util.automaton.DaciukMihovAutomatonBuilder; import org.apache.lucene.util.automaton.Operations; import org.apache.lucene.util.automaton.Transition; @@ -780,7 +780,7 @@ public void testPathsNotLost() throws IOException { acceptStrings.sort(Comparator.naturalOrder()); acceptStrings = acceptStrings.stream().limit(wordCount).collect(Collectors.toList()); - Automaton nonFlattenedAutomaton = DaciukMihovAutomatonBuilder.build(acceptStrings); + Automaton nonFlattenedAutomaton = Automata.makeStringUnion(acceptStrings); TokenStream ts = AutomatonToTokenStream.toTokenStream(nonFlattenedAutomaton); TokenStream flattenedTokenStream = new FlattenGraphFilter(ts); diff --git a/lucene/analysis/common/src/test/org/apache/lucene/analysis/hunspell/TestHunspell.java b/lucene/analysis/common/src/test/org/apache/lucene/analysis/hunspell/TestHunspell.java index e160cd7851ce..7bee301837f8 100644 --- a/lucene/analysis/common/src/test/org/apache/lucene/analysis/hunspell/TestHunspell.java +++ b/lucene/analysis/common/src/test/org/apache/lucene/analysis/hunspell/TestHunspell.java @@ -31,6 +31,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.CancellationException; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; @@ -74,7 +75,8 @@ public void testCustomCheckCanceledGivesPartialResult() throws Exception { }; Hunspell hunspell = new Hunspell(dictionary, RETURN_PARTIAL_RESULT, checkCanceled); - assertEquals(expected, hunspell.suggest("apac")); + // pass a long timeout so that slower CI servers are more predictable. + assertEquals(expected, hunspell.suggest("apac", TimeUnit.DAYS.toMillis(1))); counter.set(0); var e = diff --git a/lucene/analysis/common/src/test/org/apache/lucene/analysis/synonym/word2vec/TestDl4jModelReader.java b/lucene/analysis/common/src/test/org/apache/lucene/analysis/synonym/word2vec/TestDl4jModelReader.java new file mode 100644 index 000000000000..213dcdaccd33 --- /dev/null +++ b/lucene/analysis/common/src/test/org/apache/lucene/analysis/synonym/word2vec/TestDl4jModelReader.java @@ -0,0 +1,98 @@ +/* + * 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. + */ +/* + * 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.analysis.synonym.word2vec; + +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import org.apache.lucene.tests.util.LuceneTestCase; +import org.apache.lucene.util.BytesRef; +import org.junit.Test; + +public class TestDl4jModelReader extends LuceneTestCase { + + private static final String MODEL_FILE = "word2vec-model.zip"; + private static final String MODEL_EMPTY_FILE = "word2vec-empty-model.zip"; + private static final String CORRUPTED_VECTOR_DIMENSION_MODEL_FILE = + "word2vec-corrupted-vector-dimension-model.zip"; + + InputStream stream = TestDl4jModelReader.class.getResourceAsStream(MODEL_FILE); + Dl4jModelReader unit = new Dl4jModelReader(stream); + + @Test + public void read_zipFileWithMetadata_shouldReturnDictionarySize() throws Exception { + Word2VecModel model = unit.read(); + long expectedDictionarySize = 235; + assertEquals(expectedDictionarySize, model.size()); + } + + @Test + public void read_zipFileWithMetadata_shouldReturnVectorLength() throws Exception { + Word2VecModel model = unit.read(); + int expectedVectorDimension = 100; + assertEquals(expectedVectorDimension, model.dimension()); + } + + @Test + public void read_zipFile_shouldReturnDecodedTerm() throws Exception { + Word2VecModel model = unit.read(); + BytesRef expectedDecodedFirstTerm = new BytesRef("it"); + assertEquals(expectedDecodedFirstTerm, model.termValue(0)); + } + + @Test + public void decodeTerm_encodedTerm_shouldReturnDecodedTerm() throws Exception { + byte[] originalInput = "lucene".getBytes(StandardCharsets.UTF_8); + String B64encodedLuceneTerm = Base64.getEncoder().encodeToString(originalInput); + String word2vecEncodedLuceneTerm = "B64:" + B64encodedLuceneTerm; + assertEquals(new BytesRef("lucene"), Dl4jModelReader.decodeB64Term(word2vecEncodedLuceneTerm)); + } + + @Test + public void read_EmptyZipFile_shouldThrowException() throws Exception { + try (InputStream stream = TestDl4jModelReader.class.getResourceAsStream(MODEL_EMPTY_FILE)) { + Dl4jModelReader unit = new Dl4jModelReader(stream); + expectThrows(IllegalArgumentException.class, unit::read); + } + } + + @Test + public void read_corruptedVectorDimensionModelFile_shouldThrowException() throws Exception { + try (InputStream stream = + TestDl4jModelReader.class.getResourceAsStream(CORRUPTED_VECTOR_DIMENSION_MODEL_FILE)) { + Dl4jModelReader unit = new Dl4jModelReader(stream); + expectThrows(RuntimeException.class, unit::read); + } + } +} diff --git a/lucene/analysis/common/src/test/org/apache/lucene/analysis/synonym/word2vec/TestWord2VecSynonymFilter.java b/lucene/analysis/common/src/test/org/apache/lucene/analysis/synonym/word2vec/TestWord2VecSynonymFilter.java new file mode 100644 index 000000000000..3999931dd758 --- /dev/null +++ b/lucene/analysis/common/src/test/org/apache/lucene/analysis/synonym/word2vec/TestWord2VecSynonymFilter.java @@ -0,0 +1,152 @@ +/* + * 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.analysis.synonym.word2vec; + +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.analysis.Tokenizer; +import org.apache.lucene.tests.analysis.BaseTokenStreamTestCase; +import org.apache.lucene.tests.analysis.MockTokenizer; +import org.apache.lucene.util.BytesRef; +import org.apache.lucene.util.TermAndVector; +import org.junit.Test; + +public class TestWord2VecSynonymFilter extends BaseTokenStreamTestCase { + + @Test + public void synonymExpansion_oneCandidate_shouldBeExpandedWithinThreshold() throws Exception { + int maxSynonymPerTerm = 10; + float minAcceptedSimilarity = 0.9f; + Word2VecModel model = new Word2VecModel(6, 2); + model.addTermAndVector(new TermAndVector(new BytesRef("a"), new float[] {10, 10})); + model.addTermAndVector(new TermAndVector(new BytesRef("b"), new float[] {10, 8})); + model.addTermAndVector(new TermAndVector(new BytesRef("c"), new float[] {9, 10})); + model.addTermAndVector(new TermAndVector(new BytesRef("d"), new float[] {1, 1})); + model.addTermAndVector(new TermAndVector(new BytesRef("e"), new float[] {99, 101})); + model.addTermAndVector(new TermAndVector(new BytesRef("f"), new float[] {-1, 10})); + + Word2VecSynonymProvider synonymProvider = new Word2VecSynonymProvider(model); + + Analyzer a = getAnalyzer(synonymProvider, maxSynonymPerTerm, minAcceptedSimilarity); + assertAnalyzesTo( + a, + "pre a post", // input + new String[] {"pre", "a", "d", "e", "c", "b", "post"}, // output + new int[] {0, 4, 4, 4, 4, 4, 6}, // start offset + new int[] {3, 5, 5, 5, 5, 5, 10}, // end offset + new String[] {"word", "word", "SYNONYM", "SYNONYM", "SYNONYM", "SYNONYM", "word"}, // types + new int[] {1, 1, 0, 0, 0, 0, 1}, // posIncrements + new int[] {1, 1, 1, 1, 1, 1, 1}); // posLenghts + a.close(); + } + + @Test + public void synonymExpansion_oneCandidate_shouldBeExpandedWithTopKSynonyms() throws Exception { + int maxSynonymPerTerm = 2; + float minAcceptedSimilarity = 0.9f; + Word2VecModel model = new Word2VecModel(5, 2); + model.addTermAndVector(new TermAndVector(new BytesRef("a"), new float[] {10, 10})); + model.addTermAndVector(new TermAndVector(new BytesRef("b"), new float[] {10, 8})); + model.addTermAndVector(new TermAndVector(new BytesRef("c"), new float[] {9, 10})); + model.addTermAndVector(new TermAndVector(new BytesRef("d"), new float[] {1, 1})); + model.addTermAndVector(new TermAndVector(new BytesRef("e"), new float[] {99, 101})); + + Word2VecSynonymProvider synonymProvider = new Word2VecSynonymProvider(model); + + Analyzer a = getAnalyzer(synonymProvider, maxSynonymPerTerm, minAcceptedSimilarity); + assertAnalyzesTo( + a, + "pre a post", // input + new String[] {"pre", "a", "d", "e", "post"}, // output + new int[] {0, 4, 4, 4, 6}, // start offset + new int[] {3, 5, 5, 5, 10}, // end offset + new String[] {"word", "word", "SYNONYM", "SYNONYM", "word"}, // types + new int[] {1, 1, 0, 0, 1}, // posIncrements + new int[] {1, 1, 1, 1, 1}); // posLenghts + a.close(); + } + + @Test + public void synonymExpansion_twoCandidates_shouldBothBeExpanded() throws Exception { + Word2VecModel model = new Word2VecModel(8, 2); + model.addTermAndVector(new TermAndVector(new BytesRef("a"), new float[] {10, 10})); + model.addTermAndVector(new TermAndVector(new BytesRef("b"), new float[] {10, 8})); + model.addTermAndVector(new TermAndVector(new BytesRef("c"), new float[] {9, 10})); + model.addTermAndVector(new TermAndVector(new BytesRef("d"), new float[] {1, 1})); + model.addTermAndVector(new TermAndVector(new BytesRef("e"), new float[] {99, 101})); + model.addTermAndVector(new TermAndVector(new BytesRef("f"), new float[] {1, 10})); + model.addTermAndVector(new TermAndVector(new BytesRef("post"), new float[] {-10, -11})); + model.addTermAndVector(new TermAndVector(new BytesRef("after"), new float[] {-8, -10})); + + Word2VecSynonymProvider synonymProvider = new Word2VecSynonymProvider(model); + + Analyzer a = getAnalyzer(synonymProvider, 10, 0.9f); + assertAnalyzesTo( + a, + "pre a post", // input + new String[] {"pre", "a", "d", "e", "c", "b", "post", "after"}, // output + new int[] {0, 4, 4, 4, 4, 4, 6, 6}, // start offset + new int[] {3, 5, 5, 5, 5, 5, 10, 10}, // end offset + new String[] { // types + "word", "word", "SYNONYM", "SYNONYM", "SYNONYM", "SYNONYM", "word", "SYNONYM" + }, + new int[] {1, 1, 0, 0, 0, 0, 1, 0}, // posIncrements + new int[] {1, 1, 1, 1, 1, 1, 1, 1}); // posLengths + a.close(); + } + + @Test + public void synonymExpansion_forMinAcceptedSimilarity_shouldExpandToNoneSynonyms() + throws Exception { + Word2VecModel model = new Word2VecModel(4, 2); + model.addTermAndVector(new TermAndVector(new BytesRef("a"), new float[] {10, 10})); + model.addTermAndVector(new TermAndVector(new BytesRef("b"), new float[] {-10, -8})); + model.addTermAndVector(new TermAndVector(new BytesRef("c"), new float[] {-9, -10})); + model.addTermAndVector(new TermAndVector(new BytesRef("f"), new float[] {-1, -10})); + + Word2VecSynonymProvider synonymProvider = new Word2VecSynonymProvider(model); + + Analyzer a = getAnalyzer(synonymProvider, 10, 0.8f); + assertAnalyzesTo( + a, + "pre a post", // input + new String[] {"pre", "a", "post"}, // output + new int[] {0, 4, 6}, // start offset + new int[] {3, 5, 10}, // end offset + new String[] {"word", "word", "word"}, // types + new int[] {1, 1, 1}, // posIncrements + new int[] {1, 1, 1}); // posLengths + a.close(); + } + + private Analyzer getAnalyzer( + Word2VecSynonymProvider synonymProvider, + int maxSynonymsPerTerm, + float minAcceptedSimilarity) { + return new Analyzer() { + @Override + protected TokenStreamComponents createComponents(String fieldName) { + Tokenizer tokenizer = new MockTokenizer(MockTokenizer.WHITESPACE, false); + // Make a local variable so testRandomHuge doesn't share it across threads! + Word2VecSynonymFilter synFilter = + new Word2VecSynonymFilter( + tokenizer, synonymProvider, maxSynonymsPerTerm, minAcceptedSimilarity); + return new TokenStreamComponents(tokenizer, synFilter); + } + }; + } +} diff --git a/lucene/analysis/common/src/test/org/apache/lucene/analysis/synonym/word2vec/TestWord2VecSynonymFilterFactory.java b/lucene/analysis/common/src/test/org/apache/lucene/analysis/synonym/word2vec/TestWord2VecSynonymFilterFactory.java new file mode 100644 index 000000000000..007fedf4abed --- /dev/null +++ b/lucene/analysis/common/src/test/org/apache/lucene/analysis/synonym/word2vec/TestWord2VecSynonymFilterFactory.java @@ -0,0 +1,159 @@ +/* + * 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.analysis.synonym.word2vec; + +import org.apache.lucene.tests.analysis.BaseTokenStreamFactoryTestCase; +import org.apache.lucene.util.ClasspathResourceLoader; +import org.apache.lucene.util.ResourceLoader; +import org.junit.Test; + +public class TestWord2VecSynonymFilterFactory extends BaseTokenStreamFactoryTestCase { + + public static final String FACTORY_NAME = "Word2VecSynonym"; + private static final String WORD2VEC_MODEL_FILE = "word2vec-model.zip"; + + @Test + public void testInform() throws Exception { + ResourceLoader loader = new ClasspathResourceLoader(getClass()); + assertTrue("loader is null and it shouldn't be", loader != null); + Word2VecSynonymFilterFactory factory = + (Word2VecSynonymFilterFactory) + tokenFilterFactory( + FACTORY_NAME, "model", WORD2VEC_MODEL_FILE, "minAcceptedSimilarity", "0.7"); + + Word2VecSynonymProvider synonymProvider = factory.getSynonymProvider(); + assertNotEquals(null, synonymProvider); + } + + @Test + public void missingRequiredArgument_shouldThrowException() throws Exception { + IllegalArgumentException expected = + expectThrows( + IllegalArgumentException.class, + () -> { + tokenFilterFactory( + FACTORY_NAME, + "format", + "dl4j", + "minAcceptedSimilarity", + "0.7", + "maxSynonymsPerTerm", + "10"); + }); + assertTrue(expected.getMessage().contains("Configuration Error: missing parameter 'model'")); + } + + @Test + public void unsupportedModelFormat_shouldThrowException() throws Exception { + IllegalArgumentException expected = + expectThrows( + IllegalArgumentException.class, + () -> { + tokenFilterFactory( + FACTORY_NAME, "model", WORD2VEC_MODEL_FILE, "format", "bogusValue"); + }); + assertTrue(expected.getMessage().contains("Model format 'BOGUSVALUE' not supported")); + } + + @Test + public void bogusArgument_shouldThrowException() throws Exception { + IllegalArgumentException expected = + expectThrows( + IllegalArgumentException.class, + () -> { + tokenFilterFactory( + FACTORY_NAME, "model", WORD2VEC_MODEL_FILE, "bogusArg", "bogusValue"); + }); + assertTrue(expected.getMessage().contains("Unknown parameters")); + } + + @Test + public void illegalArguments_shouldThrowException() throws Exception { + IllegalArgumentException expected = + expectThrows( + IllegalArgumentException.class, + () -> { + tokenFilterFactory( + FACTORY_NAME, + "model", + WORD2VEC_MODEL_FILE, + "minAcceptedSimilarity", + "2", + "maxSynonymsPerTerm", + "10"); + }); + assertTrue( + expected + .getMessage() + .contains("minAcceptedSimilarity must be in the range (0, 1]. Found: 2")); + + expected = + expectThrows( + IllegalArgumentException.class, + () -> { + tokenFilterFactory( + FACTORY_NAME, + "model", + WORD2VEC_MODEL_FILE, + "minAcceptedSimilarity", + "0", + "maxSynonymsPerTerm", + "10"); + }); + assertTrue( + expected + .getMessage() + .contains("minAcceptedSimilarity must be in the range (0, 1]. Found: 0")); + + expected = + expectThrows( + IllegalArgumentException.class, + () -> { + tokenFilterFactory( + FACTORY_NAME, + "model", + WORD2VEC_MODEL_FILE, + "minAcceptedSimilarity", + "0.7", + "maxSynonymsPerTerm", + "-1"); + }); + assertTrue( + expected + .getMessage() + .contains("maxSynonymsPerTerm must be a positive integer greater than 0. Found: -1")); + + expected = + expectThrows( + IllegalArgumentException.class, + () -> { + tokenFilterFactory( + FACTORY_NAME, + "model", + WORD2VEC_MODEL_FILE, + "minAcceptedSimilarity", + "0.7", + "maxSynonymsPerTerm", + "0"); + }); + assertTrue( + expected + .getMessage() + .contains("maxSynonymsPerTerm must be a positive integer greater than 0. Found: 0")); + } +} diff --git a/lucene/analysis/common/src/test/org/apache/lucene/analysis/synonym/word2vec/TestWord2VecSynonymProvider.java b/lucene/analysis/common/src/test/org/apache/lucene/analysis/synonym/word2vec/TestWord2VecSynonymProvider.java new file mode 100644 index 000000000000..3e7e6bce07a3 --- /dev/null +++ b/lucene/analysis/common/src/test/org/apache/lucene/analysis/synonym/word2vec/TestWord2VecSynonymProvider.java @@ -0,0 +1,131 @@ +/* + * 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.analysis.synonym.word2vec; + +import java.io.IOException; +import java.util.List; +import org.apache.lucene.tests.util.LuceneTestCase; +import org.apache.lucene.util.BytesRef; +import org.apache.lucene.util.TermAndVector; +import org.junit.Test; + +public class TestWord2VecSynonymProvider extends LuceneTestCase { + + private static final int MAX_SYNONYMS_PER_TERM = 10; + private static final float MIN_ACCEPTED_SIMILARITY = 0.85f; + + private final Word2VecSynonymProvider unit; + + public TestWord2VecSynonymProvider() throws IOException { + Word2VecModel model = new Word2VecModel(2, 3); + model.addTermAndVector(new TermAndVector(new BytesRef("a"), new float[] {0.24f, 0.78f, 0.28f})); + model.addTermAndVector(new TermAndVector(new BytesRef("b"), new float[] {0.44f, 0.01f, 0.81f})); + unit = new Word2VecSynonymProvider(model); + } + + @Test + public void getSynonyms_nullToken_shouldThrowException() { + expectThrows( + IllegalArgumentException.class, + () -> unit.getSynonyms(null, MAX_SYNONYMS_PER_TERM, MIN_ACCEPTED_SIMILARITY)); + } + + @Test + public void getSynonyms_shouldReturnSynonymsBasedOnMinAcceptedSimilarity() throws Exception { + Word2VecModel model = new Word2VecModel(6, 2); + model.addTermAndVector(new TermAndVector(new BytesRef("a"), new float[] {10, 10})); + model.addTermAndVector(new TermAndVector(new BytesRef("b"), new float[] {10, 8})); + model.addTermAndVector(new TermAndVector(new BytesRef("c"), new float[] {9, 10})); + model.addTermAndVector(new TermAndVector(new BytesRef("d"), new float[] {1, 1})); + model.addTermAndVector(new TermAndVector(new BytesRef("e"), new float[] {99, 101})); + model.addTermAndVector(new TermAndVector(new BytesRef("f"), new float[] {-1, 10})); + + Word2VecSynonymProvider unit = new Word2VecSynonymProvider(model); + + BytesRef inputTerm = new BytesRef("a"); + String[] expectedSynonyms = {"d", "e", "c", "b"}; + List actualSynonymsResults = + unit.getSynonyms(inputTerm, MAX_SYNONYMS_PER_TERM, MIN_ACCEPTED_SIMILARITY); + + assertEquals(4, actualSynonymsResults.size()); + for (int i = 0; i < expectedSynonyms.length; i++) { + assertEquals(new BytesRef(expectedSynonyms[i]), actualSynonymsResults.get(i).term); + } + } + + @Test + public void getSynonyms_shouldReturnSynonymsBoost() throws Exception { + Word2VecModel model = new Word2VecModel(3, 2); + model.addTermAndVector(new TermAndVector(new BytesRef("a"), new float[] {10, 10})); + model.addTermAndVector(new TermAndVector(new BytesRef("b"), new float[] {1, 1})); + model.addTermAndVector(new TermAndVector(new BytesRef("c"), new float[] {99, 101})); + + Word2VecSynonymProvider unit = new Word2VecSynonymProvider(model); + + BytesRef inputTerm = new BytesRef("a"); + List actualSynonymsResults = + unit.getSynonyms(inputTerm, MAX_SYNONYMS_PER_TERM, MIN_ACCEPTED_SIMILARITY); + + BytesRef expectedFirstSynonymTerm = new BytesRef("b"); + double expectedFirstSynonymBoost = 1.0; + assertEquals(expectedFirstSynonymTerm, actualSynonymsResults.get(0).term); + assertEquals(expectedFirstSynonymBoost, actualSynonymsResults.get(0).boost, 0.001f); + } + + @Test + public void noSynonymsWithinAcceptedSimilarity_shouldReturnNoSynonyms() throws Exception { + Word2VecModel model = new Word2VecModel(4, 2); + model.addTermAndVector(new TermAndVector(new BytesRef("a"), new float[] {10, 10})); + model.addTermAndVector(new TermAndVector(new BytesRef("b"), new float[] {-10, -8})); + model.addTermAndVector(new TermAndVector(new BytesRef("c"), new float[] {-9, -10})); + model.addTermAndVector(new TermAndVector(new BytesRef("d"), new float[] {6, -6})); + + Word2VecSynonymProvider unit = new Word2VecSynonymProvider(model); + + BytesRef inputTerm = newBytesRef("a"); + List actualSynonymsResults = + unit.getSynonyms(inputTerm, MAX_SYNONYMS_PER_TERM, MIN_ACCEPTED_SIMILARITY); + assertEquals(0, actualSynonymsResults.size()); + } + + @Test + public void testModel_shouldReturnNormalizedVectors() { + Word2VecModel model = new Word2VecModel(4, 2); + model.addTermAndVector(new TermAndVector(new BytesRef("a"), new float[] {10, 10})); + model.addTermAndVector(new TermAndVector(new BytesRef("b"), new float[] {10, 8})); + model.addTermAndVector(new TermAndVector(new BytesRef("c"), new float[] {9, 10})); + model.addTermAndVector(new TermAndVector(new BytesRef("f"), new float[] {-1, 10})); + + float[] vectorIdA = model.vectorValue(new BytesRef("a")); + float[] vectorIdF = model.vectorValue(new BytesRef("f")); + assertArrayEquals(new float[] {0.70710f, 0.70710f}, vectorIdA, 0.001f); + assertArrayEquals(new float[] {-0.0995f, 0.99503f}, vectorIdF, 0.001f); + } + + @Test + public void normalizedVector_shouldReturnModule1() { + TermAndVector synonymTerm = new TermAndVector(new BytesRef("a"), new float[] {10, 10}); + synonymTerm.normalizeVector(); + float[] vector = synonymTerm.getVector(); + float len = 0; + for (int i = 0; i < vector.length; i++) { + len += vector[i] * vector[i]; + } + assertEquals(1, Math.sqrt(len), 0.0001f); + } +} diff --git a/lucene/analysis/common/src/test/org/apache/lucene/analysis/synonym/word2vec/word2vec-corrupted-vector-dimension-model.zip b/lucene/analysis/common/src/test/org/apache/lucene/analysis/synonym/word2vec/word2vec-corrupted-vector-dimension-model.zip new file mode 100644 index 0000000000000000000000000000000000000000..e25693dd83cfa1157796c0f14d623c4f7a6ce930 GIT binary patch literal 323 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

azUD0uco;L<2rwmFD-P}nlGLlYitA6+}D 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Π($M5x2`HAmH+P%rv53d^4X<3446 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

fj> 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
W`y4n7b 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≦A(l}ivs~NK28_@ku;kH|`D1GJ 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�m3^%+7 z-Hop38bo@);%;0w{I-n^-RO$u_sGpPa}%%H8i}{fe^W!FXea9Qz79h`KS}zSoR?9y zuaV*_i+xyc`@1b6=!_kq$yEKkt2$MbQR7S^Fi^2i-UB;Mr3Q))VcMMq^q)#Ek7&jdKh&SYFq-0E z$vO5XtXod}C7ZtOt&PJn6<)-@U7gO$(PN))JF^b{BNt>BlTiq!hH^g}nShDR1Yb`` zIp=YE>P5QZtTSFn@=(UEOyqHO>~Je>f-LB@?84ICiHu=Y(*{}Ptqrhc4^TH`5K#gJ zK`ozul*Q!|m4_ul1xw;?TwW|29u@=Ny@^Q94;gsc$hR}7TQBh@vm(&0Ttj3oL^%hG zZ&q$+6&TO;FC52D@<#O&%U%9in8O=UGFwE0e{RJ};_1#Nedk-XkwnbMsW(dK-3#c}k2)t>O-NvY1+Mo zlF2>Wwsg?%+EG%(WS9T*`ZlBw(A>XdA+k*5(gmdS#?fL}J5I3u2=1OJ=F8vH<>=l0 zCd;IQkgy3UBPaXdS@Gg*kQgUlS8Iwl!OvuDGC-4u;0HmG>1=@fm zSuta$$4`2+xV+*jV4PmbK!&}fD!&ru^jy8P&Eb~6*(aZp%|eR{%&U|S@u~qY=MY|c zL_w)~*wxsJqJ36WLpG;vtne-=V{$JRsDr!T++~sd8ZEDJZcm-hr9js7b``z^!Df?Y zsC~yu6`qo>NEvlRU`2~0Qkz+^2D3mEj)bV-$4`Rxwq#Fv1RS@;(wa=++u0w8V>eXd zYKVoFaWQ=ZHA5}!G!c2u*2^E}%2~U-tX21o|Lo~X_fL{-WYB=hh&cPo%{<|#&S?7& z5Br;?)9;)00{mVwC6J>@d&L+}kJ#BLm8+`uUelTv5+bMlJVP0sq-8zao>r5@pdFSG z2SYf$@4L+#Y-gQd+)u`4xafyK<#|dgQ4&C&2+xFeYlE6ann&W<$KnH)qN%)noJ$&L z$ZoMy55?bIril%E0(0pmK1{8jNM{e@v>%_g&mn=Rct63K{F8~kRkMgiYuvXstjxBb zEJ>yAt#u{&KN9rae^;S4pE_5sMlK=KK-Mz0=Pn@x` z3Hi__uRK)V%eZT|Ik2*Le22f7k>r!}LLJ?6{D{lT0VXG6#ISfc!7TFJWLyX)MQ(Q` z+%5x`e3-eulT_4fWn}}+IWW%Mg~6{cz|(jV#WgD&@Ej~@5XqdljVl6QCx1ES`MJ{p z8)hf1Aun^p;b4!`S^U#A5%CO9Tc>!`N&JDdFD7_}5qT_h6uNmHFz1jNG`nR@Q* zC%)Tc7ViC#4G0pgjKVO`enw|}4wViOT;YF9I6H-_KkEnpNa2a({kk0({vLveCShIP z?uIEb*^}Xr?q*abu4kvds%WFTsU;q0Lv+BZs~ICA4c}QkcCZfMXG0xH<7AMtZ@IJC z>dqnEn<A~YIsc_KwAdR1D@c!-DxuGK{U8ec_1W~GcAtQJFN*<$h>)63OL4l)KE z=-HFUoc`#cNVL>{_A<*($m=y|y3A!dW=O>vmrowm*8L)FrG%yK8H~hx*Pvm|{gyMX zLCFeV4B@0`HB$0yTttHS=pTgwJ~2*B_@VKWOU=HeceBGzs!IY;Mwtyb=G4yy@VGvs zHpcB59y9D^_TwlUr6-z&4glLi^`Z`pQ@RbpuWWWT(-y_i@h5i#_r)zykjC+vEYPTd zckRydsi{?4P-e^mp4Pluv`PGloxCU7P9j!#SSrl^lf*e|Lp!E5VH6^Zn|l8XKs-#Z zR|xAv)zgnY&`w3aVa>kGIVEi%*d1v--LpO6CF7Oo9=CaAOwzIzxt9sn^odwxD0(LF zWRb-pnSg%JFEZ0eK`6G9T$?uLZSE4dBbg$)$o!DZfn-EC^weI(Jf-U8Cl4Vp{j+Vg zxY1@-4Wb4FR2$%bo@u)%8-GXtnHlUhml6E%YkHPyv~Rjdbtei5j&Q; zsju_=1e#9<3rFH?k9KxTSTsa9)8HCxutqeManKeJq7(p}oH4dO>yqA_aV!a zg*t8++x{jY(p>5HmJazdakbp+F$DDM0r(G=;YlQ)&jhVR*F`SVE;IRZ^knyp73>Co zf4V&Te{()<@765t5_b7~r7+74J2h2rHIcMngj#nj@>knTFHmkUE7%;Rp`gP#Y~lF! znjqtVcBQPT_>Z*A^STaBJSQYs5q$EteIuV`OZJgpV=FoAS6kUjTmj54T{dL*YGm?+ zKUIY#1^yM?{Aoy?gUY-fZeSk`D_Ca^T-E74E^ z9)G#MYeGPs=jOy?QB9k;C(JR9?A92uPo6LUgkN1#+li$-`^Z3+-o8asuU|Pkqv$=k zC^xdaEQisNnN`~~yCx>BAPR6K;Y`fmy}2_B>J6LO6T16^JSJ#b8~cQ{pVC@#$EF(G zhxw;b)ewd`^}K_8_M+|Z?4%{5RU?7_wd3!Eak1@X^rTJ=b~RrcG0HB2*+i#v$;7#* z0sq%c{p^vY`P-{A;wIQFUZ3xFaRB=;cu2sf*OnP|INV9^yguK=jVg15A+lD+DtZ|& z3aeEF!ch4+vn(p#zw+i2XzUZzZZVR&hD|iNVeT(i=150#0BIoXRQAtRi7}CN&|#D; zGhDw(e*XK;J4*gt{t@DWnrDaQXC{&0lYdp_lhQ{$b%X&hu;kw4KBFu^Z8_GVdVcL_3LEWN@{z6F8Q4&|d@A(aqX(Yt1Y z(M6y_wKM@0ONOeWaZIY2Uxz_57(Wv=9KMCD;qR#N$oeiu!!?$1s(}4s1_NO;XSXKf;VL<=cAE zy21iGHxr)_jx-_$4jC_{%2AhV`QMnm$Mwuee{pa?LpJ?`)J9SRd$5`+I<9V?zfVCI1#0O2Q}2$GxGGGPTCf?g$atQU9b#_!8$g+1fi=ng{6t z*W~yJ4HgYLZg#}U9C4wbOhRDW>-GzGkDUSX{uRBkKqzZ>r{jAz6=Bh*+ssF3F|>KP zh0uIkD2P2;?fz}CX;7|xvI`N&3F4(a{m#e!HAcawLN1oZ80E~C4crr9-et`1fo5+| zx8296ocGu*9H8MvOdO=nS~Eq*H(B!heoNASAo+V>(0wTK#jz&f#Tg<`$Km|zrj{vI zB8fR1Dx0&ESxBCWH}mWMDK-@ghnBS;RGBHc67+@L9A^)9ps`7=)` zh2Xf6*cdX|T3adik$lq~>DsK!+N<5-o}<{*cW2_0TwqVAG0pu&Ll}wx-Fp28y+`{( zQsi`*OZ;it+7VN^@L`!}MBrrK74`fXiAmP(8`WP|8V9u5h$#0=@g_i{wX0f}DF5ni~{Oo@rczN^9cA-Yt@a!gDYuZ*FD*m}_EiJ8DFYd6Gpql_x3No0|PJoc^i=!0aH* zw)M-XU=}=G?ECYDzZ-D!HxcoF0c>VC7d|Q#@^OxV%0wKGl5JuFd8wtT6nvX_7wxBW zqd2kO5=H||hubA!%Uor)ULDw4)txoaJBbPVaNa&-{~Po-b7aDo=F}z6P+VrBmER3X zFK-3`NO$MwY<(G^2N~9s1QfRA43s(jopSz6VhzZBwCbd~ceI3v7&)1Byj2x!CtpD?A-CLTB72_dRA}|kA^bge%{|(%bMI~shM}jolhQwHmT{g?9zuE1?&5Y{ zPDT4?{t*kPKiRD>VbsI4?<3v8O}yX#BxA1`-z28gw0hp3FjYf3bK=&NX)bjqlstNo zx=l~UL!kqZ2YD84MNjh+(bpp%gEG{hfap0hCyc^*b|qM59m>lFRqlKgMA{)Q2S%*s zF+~hT3z@k7VeZIU_T9JEpla4nhe|nOJrS(u^SRmqJ*wNUNFcxdZr98myUn^j7?DF# zy3pawu^5Dj+h936x0UT_-l@LG&ym0MG{Jt!y8N%4jiQ`?zd|tO$4rK$)Y2ST;cmlX z%9O!)B&54PIgx4TtvbTHwsRmu6f_ge_}TtV0n_VGRY*?;bCTk``)VoUJ&Db>2|Uvu9gfg)EtAJ zSyjT3?maJy{7}c!8no0ufq^FNgw0{n!;Mi9sJq0Tv{&MC9*1=^<*x2hwMG+yZhl9d)Xw>%JRY0(rH)e*umm(~*mB z0US|i=8rATO5EON38k9q#F9sOreCrc$X$aI9Csz(yf}3(8LH;qhaNUlLF^`|*q$SM z#zAC5I0St!f6pUni2LhkqF44Wmv9qKohyfn8u8NVw7#9)#vc3_1>w~M7Vm-3SK#%s zhjQ2RhAqL^Eys7J5jF&OVmVUh2jQi5cq=gA*TV@fW58cR(8}F%BvgRpn#SX!cX&u3 zr9?h{v`jmuJ)vGzx%#0fFY$Ry|s zK}Z@O<=9_rrYDPzH361l1w-OnGj-cz0&dKVX_WEAz}NGtdFb@1W-n#w*)Thi6p4KP z?fjDU7mN8ePhJ9{*PK)|B6l7WUYJz;j)Dm~&w*n7B?@pn32$cBC?QwFfL6U%UJKg& zq3O6CbU5g{PVIc^Y{SQyi~gKo$|Zs^t@-Z?&<%Q0^li{a|KTMVAt+HpvKpGHA+Mjy z-pk}RcfC9HFjy`#J?P$Bv^#_$rBo}zMD5Ybi5xn#*JY!!dt>>vGrxieY%<8uPFM&8m@A-ihRHImmqMEij)NVAvYVE=EeC+*?-<~3$kO{L4-Ra>&N~Et~PnpiZj|Y6kl_-6y?E;paaY>??yMvBj*HFYSUe6Ks zb7*r1H++s&RT#Nbl5GmG$EFTX@zpZFPZ=@%WW0Bvb@?S|M)g0yA+uN!>q)RTJ@H; z;Cu7vH?Jmb9+L`2Zm8bg-IKF5f*lL&Y0E{MCqBs@#HUr%wepBx#vF!jA*HQETyK#f z^71(VnjHT7K;M7~^U;}&zjQ?Ong2vH0miWFOkAgZ2QC*@Msix`Y?_s}EDwdWrj``H zaPK)o-u2rx!I7x|_%M%A3)5Q&eRfE9(oRYP#CV?_X6I^L(y!(D`Xio!Q4x)AgK$#P zfu~V#J(K)sN5;r#+4PNrVml)5-j?$G&N%7R>d!t~5e6-LtiX1UGPFgw3EopoK5v1g zDt)r@+0e!MZNp0HUZueH|82Fd(=R`h3htfGBHq`zU+su(;gD_2?3cNp#jGp1v>Dg( z;a_onU2aOVt@&to=1)6RO23sOn?77g^Z5xiQFfbRp4r``^*IBg+Wyl@H)Xq+U>WBn z@{k%^0%n7?4x~K6g8DadwFxbw$zpBdW@z;Ub*=h}Yk$OULYmCo;}v@5ZAAe~t^%3k za0^8?u<_ee?j{MXbJ50P$~+Qfwnn1=>hy>WDE??;-pJ{rQXC$d2;%?5Kd=3L1e~No2D>*^)0PS1wMqFYS6s9vXyXe%J`eFt7GkT|4;7c)b)3kfJ%ONqHD&u z=G6rCUW`yRMIf zzF)MkQOxuLAc{QPP-h~;awa}k3|?1?^)zQ#fUk!LSntaKGeFG01|m;t=16ILaK~|( z?=f7oqLHSv&3lGM`+fu|jyeC{-$c%j zjwR3LpPx5xP8?MGIvXaUqwJuPn0idSpf$64)o5+(@kf_mhYa?-%Kul|z@3(Xq~)E; z=+4fH3&~4*?UQN1+3;_UZ~Cs*pUUm4RP$tk@K%NrHvpAXgbL;ac2so#7V@TU`K10! zSfV_^-pga0T#0#tYF;zrZ?E|K@vuAWTc2xGU2u4Sk!YN6&Bu46NJ#F@kcLwTTuF&+ zShCbUNnXb&bpA_}(?o?jpzQdnUeB>T`kfuTm+d$+*@#g1&iQNbO}w)vd~H&nU6;1o zzgu{pP>;w*Ga@uwtJt5Bjp4yxwe}H3(Y;b4+3<~Hkv{y6b6_oXHI?cei{EJHdvlo@ z>zV$OO+poNMT5llpae$SEErR|jHVd@@7{e)G~e*X@*V@rzl zKb_J90c_iU57lT-*PfZ-`vo*quc|R6cPx(MOp~}9+L$)J5xrP|+=juL(_T3dF6}v? zCu@r2W4pr6J$=VL)I)>p{1* zQ{zZXLGx3R$1H3C)~*zz%+}$*H&owTJDJ|-ZFj}(4CegxhGUw}ca)Y-b6!8?p?_0n z>#F=c1_J>`4TFBc89XQN#>?$NF~qX9H(7d(;Dtx59^dv2R~AZZlrCqrR90oG?)Se$ zB-ZOJ-|g6*k8(+ap5V82QhKf}(`8#jN~``T{J3wr%lqhH#n^34!XZyk*TH#Olej2G zVC)>5Cg)g#TDVMBO}H+%DhG`IUPvM>+iCd&gK$hazD zkE3t;y;v`t77@|3BsSQ0>TMr=gsgzw_D!2IzE31fEtjHtko816|H2E;52C`oy#!4# zCW`Z^kb&1@&`<_N5JtNZ{c;q?v}EJJ-g^86ow-F7*G2?}i1}|seuMdoxqj}|rFnUf z83BWjW8|z()&x+PEX>ij7(wu>7#()Pp;rcDnoN)po4!Ge9=R+A7)DtdMdyF=&)u+K zr(uonwdaQ$ukAx3P3wFQh|&KA<1V@HiZXK))*ftPpahFf)1$B7Gx}BeoSz#n z%Ir0m&#kZOL0a2wi(7RttILrLL3-Q{1MWCn)g_!~OT7nq6m`r=d&&nL%p3hJfyFi< zlUjD*YeR;8<~oF<=ycTIkkiVz&&_WPHgYP_Brktg|#mY5v|7<)&mgR^y2TVihHB-yQ4TKj6P zl9TZ+e>u%}WI0#rbK2G^T(JEcqI?%hN?Lqm!r;~(GwPxy7E zhJppB(*-$MW?4W`kPz6neR_gpi`4>@C&%9&^qtP;E`F2UB_!0xyr{M%bf!eqAI&7y zT$6-F*SOxF!|$q`_0Bc8e-rAM2OTEdTJ?Pd-Eo)8FwtXIy23YR{d)?WoJX|9tO=BY z1U5d5IhT4%(89v2s2QpWYhK@gp7Z z9)Jl7yU##J_3k4#NlKy4QB2%mLjq>I(T9*!TS-&4W;H@(StR9>^^kfnru{AvA`TEq za_5?ljIGJm?sqz^(yUMrM6t!yFgQ?Is^oK72)%J!nspgX-L;^k5E5OO^c{nNV>GUr ze_4_w(EgvUp6QC2rR<0s3Hp1i5@7(WxlRj%o4y9OG1k&Es`13{P#dlt`ZMm}Idatc zI0I|;ZGe)E-$t3Y=Pq_lRL_#k)iJ)(EEA;$$)l$Un65Mojb<*XBY1@6Lt`4J3XD?se5tcGj>OxtUG4#w5tFHq zr{3{?o5WlC-vPN)Fzi2ZCLc(s%w!y#qUPU_ZI-&&LxTO&isr)utd55(Nn7Xf70jeY z=3b!pwP_?wlY%m{hre_6%3{siRhBpLiCkg3AXC|Yf_vhGL{a@KSw3N(2qmAc$wq0AJ8G6Y@?cvNh z$BVyY-~Yr@zYp2*=}vUyTWJv&H8wr(ld^q{FM-t~q0Xb^-7{kiOZUUL=wV68HJHyMdI@chfyuoMXU zRpiOgp7R-*I^->yjC;-)qnpGAOjM#lC4YM8_(OrgD!D8IE(4ZhdTd%~Ts3!Wi%(-e z@TFt)Md?fc6s@Ug$2;UF@CPq&bUZSy2^)z+dMo@5Qw}-Hb<9kLOV8UA|V1tthrYr z8%y2aqC5ktIIb~Q@>1;PagMriUs&a0xHI3?W>#1NvKH^>7b=%4_rJMJN0u{323TY{ z{Xzm#<71NJQCsR=crwS$GAEeE&gcGgV9?TrNJDd6F@A0l2rQ&hHv;@cUN2A>|0-+aJCZ)zBh zEw;YmFG$-W6cxX*yaT3>B22l>PFfjZG~MQ;Z-6&r6t?F(0I-*?ZD6P(`giy~!=N#@ zrV{&)H&>g0uWF5WlLX`z7ao#OLwUIGuml_}Ph1J-pLY!n)Shh#J31kOccLe1uw7eg zl6M)cDVdNj`clXJir_`qF^zHuiR{^~?HcPWh$?vw zMaWEs(HDd*D#L}sr0Wl@K@2%q&N~}eCer!^82REo-vxLq-rl!Hh|uahs60VUlWph0 z>&%_>j3CdlOjM*MWb2F-@{#7rlfMq%E1}DfcdoSZfO2(E5V*?+RxLy8fw|#C`Z5;@ zG7#7F0t9lsjMOQts(Rze>@ovq!x8Iu%)jjIAo-$TF^P{P5xz+b z<}>fX8*rBGo)YU@lkf2(de6ftAEX>A#)y;WfFR?-0mtt?^@e_zYc!MC6Knf=Xcsme`vK>I%1RSTa^C$w9Zt&#Of} zj`QlVdy23o*ZAUG*AaqKcX?C{8U(|Qt~!k2f+yde_U;Qv%YO;_5zS<8b_FrmCpt^f zH~G-(km2_uN-TD5R{gP6*@h^>w^+n7HIg8vy*mr&%Xhouj2i=6=)JA|Zi7oSn3RYE zm{bmm%zf{*{XGe)bMl&naWANapM(~7G6$nuF(-gMiDA3uwGgvRvq>H@l-61@<(rJ( z^%WwIVZKox&1@hv6pR$2MP|p5zS-5k8D&07!GA(Yh-W%0xcjM0%eUnLTG|I?l5|Gc zy!d@g{`xQnnyrC1RlZ08-y)Pf@xf`l^$Ezs&zqb~0uE?cBd8Ix;^+ zCoS<)B86S*{r@y?ThfSDyK@$%Pf$jki?+O7!JYJRJHrOY>s_kGpdyOHtz)1r=UFLE zOMPUsw=an4F0`nao|=FWbL1MB$8;58ki&MuoVs=H2wqJ1kYuRE|CD~)SQLb6RM*B;5*QBr3m&xK-f<*cx zWwEgAiGMe9p1?$t&3DN;>k`UXjN(H%ZO-27Q&;+$a+~d)ncF6$Ct276U8am!5=|B% zGq%G1F=yczB~D*|4tr~I+uuN7mt&y#$;NcwX|Rt*_hoNtyGSV9n%~z%2^Os8{Ea&J zC9bIF53`m7r^+XVbvfO>@+*yesE(O<05XLP7oB4V@fb0BM6^U$8bp`J#vgA0vqixGJW#tagAXU`~x?xP9XbbywFi1p=c6NoSj zSs4+|<={1KJf`8t-V00CVlU&--*c+3XNcIF_qBqM*nfOB{M6HCkAXDf67>gWvNU-F z8OJM{T{Q0k6Umy=u%+^;p21;DHtREG`;rk=Vts6FV=NsYTk=%qLtAgHLRi{DlEGFhFS|hKfV*5og=) zyI6P+Mi(@T-e+?#K@GO1&7{J-FcwmP8OSI>zkfJ%9U&|

W47w3-WwWR7jK_fu8qZ116RE)-d{PXtY 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%0DFnc#}}xwRU1) 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

^8rvy082IChMa?g;Y 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 z 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 r`1jSwzk~nT+yArG!P>ts`` maxConn) { - diversityUpdate(nbrNbr); + Lucene90NeighborArray nbrsOfNbr = hnsw.getNeighbors(nbr); + nbrsOfNbr.add(node, neighbors.score()[i]); + if (nbrsOfNbr.size() > maxConn) { + diversityUpdate(nbrsOfNbr); } } } diff --git a/lucene/backward-codecs/src/test/org/apache/lucene/backward_codecs/lucene91/Lucene91HnswGraphBuilder.java b/lucene/backward-codecs/src/test/org/apache/lucene/backward_codecs/lucene91/Lucene91HnswGraphBuilder.java index b0e9d160457b..c82920181cc4 100644 --- a/lucene/backward-codecs/src/test/org/apache/lucene/backward_codecs/lucene91/Lucene91HnswGraphBuilder.java +++ b/lucene/backward-codecs/src/test/org/apache/lucene/backward_codecs/lucene91/Lucene91HnswGraphBuilder.java @@ -204,10 +204,10 @@ private void addDiverseNeighbors(int level, int node, NeighborQueue candidates) int size = neighbors.size(); for (int i = 0; i < size; i++) { int nbr = neighbors.node[i]; - Lucene91NeighborArray nbrNbr = hnsw.getNeighbors(level, nbr); - nbrNbr.add(node, neighbors.score[i]); - if (nbrNbr.size() > maxConn) { - diversityUpdate(nbrNbr); + Lucene91NeighborArray nbrsOfNbr = hnsw.getNeighbors(level, nbr); + nbrsOfNbr.add(node, neighbors.score[i]); + if (nbrsOfNbr.size() > maxConn) { + diversityUpdate(nbrsOfNbr); } } } diff --git a/lucene/backward-codecs/src/test/org/apache/lucene/backward_index/TestBackwardsCompatibility.java b/lucene/backward-codecs/src/test/org/apache/lucene/backward_index/TestBackwardsCompatibility.java index d030777e3783..40541f505bea 100644 --- a/lucene/backward-codecs/src/test/org/apache/lucene/backward_index/TestBackwardsCompatibility.java +++ b/lucene/backward-codecs/src/test/org/apache/lucene/backward_index/TestBackwardsCompatibility.java @@ -419,7 +419,9 @@ public void testCreateEmptyIndex() throws Exception { "9.4.2-cfs", "9.4.2-nocfs", "9.5.0-cfs", - "9.5.0-nocfs" + "9.5.0-nocfs", + "9.6.0-cfs", + "9.6.0-nocfs" }; public static String[] getOldNames() { @@ -459,7 +461,8 @@ public static String[] getOldNames() { "sorted.9.4.0", "sorted.9.4.1", "sorted.9.4.2", - "sorted.9.5.0" + "sorted.9.5.0", + "sorted.9.6.0" }; public static String[] getOldSortedNames() { diff --git a/lucene/backward-codecs/src/test/org/apache/lucene/backward_index/index.9.6.0-cfs.zip b/lucene/backward-codecs/src/test/org/apache/lucene/backward_index/index.9.6.0-cfs.zip new file mode 100644 index 0000000000000000000000000000000000000000..bc40e99b3d77193e1571531c9b768663b6c01017 GIT binary patch literal 17503 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 SY$CsX>b`Y%CvT4e0{UMj`jYDa literal 0 HcmV?d00001 diff --git a/lucene/backward-codecs/src/test/org/apache/lucene/backward_index/index.9.6.0-nocfs.zip b/lucene/backward-codecs/src/test/org/apache/lucene/backward_index/index.9.6.0-nocfs.zip new file mode 100644 index 0000000000000000000000000000000000000000..8e97a46c14859466dd25a57c6759c8df2114f711 GIT binary patch literal 17498 zcmdtJV|b<8x~?0uV%xTD+qO}$SurcNZB=YlY^!3cV!KXi%rW<=8fUJ##=g${vGz`` zp6mOO{`9BxAr{pQota{0000G045S;s$KbcA6NhZ0H%Qe0KfpS0rco;jZ95c zlpz6tGZnOqe?FYupaB3uZr^|DkLT5OWf9SyDWzqkC0kl-W@Kx{=%poZr>Q9>q-u@< zfRsx5I3(3h*ss$%3-5Xv`ym9df7aF22nPfPQ5Uj6?Wj)(2O=K?q*Yf`tpOad51M(o zq+i*Fxq(8Y^5O6It{F}?Ms=eX?0ek`HZ3-u@P!H%07cPHljgY!AMI6)m%92KzIOH5 z0ZGcYD4|f*%h%Fe(81OQ6e*AiZMdTaaSVQfkT7zB2VlNBKpbWmg&ID{b#q}qaZj{b zko_(~-JhV4+5`+sm>aI#>k}h5xUd%i>toz%0!#+{WyjJk^wnqRW`b?8n&Zi_hE0(~ za1kL|V7@@607!%~5+)FWj5TS9L<$5#_z8+;eF=^5VD>o<`QMtZtZa~P3Jm}-Lj6nA9sga^=QVw-u;y`m&et-% zI}4n**_kEc=V0hD4n+;gWR#Xkr8+7KyDLa24bu)+R|{{`mWS+@on~0Se234Gsh+Vo z6;@zoO*xFw&z$pVoUdFeK!FD)jfqjM$*Zy0j;1ew37bCaaNTh29GL} zxy&s2s0I3i=dtH2hu*%!%cT##_%NETcLEyv8<=1A5N6%e>O_VO^~oGs5=!m&>0(s$ zPnF$r7(oGTkw=D|@?9}ZUqti(xHy9{oIX{hjGv~rHO0_i2087ACL_z(ogX!gdY+** z;Q+f^@6IbKi(hy0A*GQc_UA#)!JlD2tuYyFn6dh8bkjQR+eqem#eI$7d z%t)k_lB0B~NylBe5Sg9Ojp3>%Vsk~`Zi={Q=#1fcMMn~bAf=WF910{41c87=tjMc1 zZX#H{9s@Ow3}C_C*|Z6WCe_~4DJ?Kh=*AVqqjFFU_g<%j+7_LrUx+Uw%px$2sxf7| z40~hh(AR6)UrxIgincv?z|bt`T4ZwG z?4Ii}j_zx30h2)I|4aii3di3dQco5?%%Ct((Bn03-5tFj(TB+{ zgPg-pg7Z)KlYB=3idyOWyky@EPmA>4Z zjh(b_Jy+FKme7Qi3XwhH!IKTtf)p_=0^LCRL*^zjsl8pO3nvjnN(sjiYbX}@A}1(Q zIAyv#Kx?-Iz15ywT!;+!+%7PCP>iuPmZahAP z4FaX3uem}%DkQ7I)%$NTs;TwOd{@@BUggh92+Eh$+c0-I zk2>iePNJLKeY(g$@ZqkUoS@6(z1yv?aeDIn%n<-fftfoWhbgiz_ByaoGQg|ImM(`F zMtFqCs@f51;mny$h1s(GDPQ0C0Cpc53~PQ|QNBoL9y<~WL!thdabnO@MnJ(jX!DS7 z*u9;l6Gdc&Y6E2i;!P`j)`R)xe_to@4g-n2cH7hXP6m@y7OrC`uoqqMB2s zSKzSS&8dMc8KP74CYG)$e31ea5JgX&M?d56`g^0@7YTdVlM7C>$FoZ=0Fuaa!{=Lg z0uqe@5>4Yt&{mYr3v?bJb9TVAxR?!jB=Kx`Z^ATDSpa?bD_k^qBQOxdP#{`CjSN?h z*ksa`7bw6B#yK{D^`l&gJyJq?B;Rp-Yo?fm1(2lYu?!$K06XZIR&MFa8FP!^4A7%= zd~>Yoipvj(z}2+5zI6cT!2GT{X+cMOfqOkB@XWB(r=4k1rqx-2pc>fcOTn&e33Pzt zyv#n1w@$@7FB}q+9KkkOab%2++iuF<;-XD6-kVtL&tfloep>`dU?E70d6Z|ixgj*q z%wf6cnG_5RA)E`jMTHYf<5q%$wT=v|g+}zlMpkJ9hXrVIUbbY}qd13{jr$G}<0sJ< zE^{uPVSNfKCE?)f{H4qx+W{++JHCn&3HHJp9+JQ=*_^Gu%&G zG>51FGVZ>e*1#|!HEH`DNLl<60Bh%f9_qf0Wo}Ajve%s|VDjvdV1SJqz<15QBr4nv zM6%ak5juf$FVv{DzXH2r+Lh0Gu`h+3&H9|apwK;3m3J-%Evv8=^at*7=!i)fiY66a zo0eM1R$QUe=|Uvry2oa-j+*fHj-KP+ut>7Fr}8(F>WLs$N?^kaA~c#5wqa9CvE$Fm zKrH|@bA+muHw!@|K8{GE&z@c3$JYLZ|);dmYYHFBSNnSx-HE2M;!wv0`nn^k6 z_C7#LEX3*HXQL$b?1cm>RYDqOj=5q-a<8Q(z;^9q+&*+BYGF?#e!Wi5fzq}w5hP~i zN8x{!Me3*ggd*xEX1f$p=dxM2kxDY?U3khn^`opEhlQsSmV867qo%YGQ;(P=o^7P# zNxE!6jj>m1DMra%oY*`Ew9XIJO{ipNZR;}OF_UxQ(nf_vIh~suw@gMBCd4v+P>H~{ z)?bnmkA#wHs-XFpq+dl1MJ-d1@^&*=%ay|QOmRSWWyxNcbIXQK@rK8EqP-NmN6HP?2bjoc#1LD4y3r{Eut zY9Dv^l{EEV1L_-KU1+)iovT0kg}*GHbZdZfU6(9-OyELrJB`W=y7t`XJ}8u9Ltt;% z&&7*VFy9lVA=BlFloBdJTWL~UE=RtJ0e0m}f*)%TF8B$zZ*=1gc%p}fR1po9R_aW>L?Yop%xMoE1$ebi8zRjrv85wS+}K2@=hAHY?`YVrhJ;J zaO;eCg3#iPq2LeaU)Qt6UyC^7RI>F!Si8^c582{HT&E6rDbhEy8F&`NxCPzHG{@5{ zAhSkhmtU1kKWLa7zmP_;rQvIAc}z_`0Xj3QA=1dSDaRtz93De6W1Z&l6e<{%Zl1&6 zq7>#KV3Pz~o6>gQTCJ#J78l^>WBycNK81p%we1NyvHapTdcRjkWzK>!R(NP?ZA#dt ze<-k0@ap6oblU1-24&gHEW$r)+$nFo=r%{wiY^hUu&^yJ`Z|MIL`kWP0-bu&`6_az zp|sNraa>|M4x?0b9HRL6*iko777TNj^U2(hHJhT!CIw7{ubxTm1DiCj4&2$u!CeEh zG~j8Flj)OhZWC)Q8tMIP3!+6zFlm{e+<-*>k}21W*YRj->0Z`jfG7c%jGUaL5wpcN z?bwY&*u&FC8iXG8MkS;t7#B){h-L0xQSO{Y<$UX#z;%U4+qA+Rn9WSt=3{)a8(Olo zShXWBN#IY`Eb9|7Q*AuNC*%8!K}7hu#mj(PLW1X&cl;+n!3zqX$^$T~$CuE13kaYD z!5vz7Ue1g=#(8RG`Ca!MqI|~dy5F#iP_}UkpSqr70&)0yzGPbST7HSnviAAz^ZP12 z?D_c;>YaK7-yfj=KqE(sf44~ggN#o8BqR8Yw5;?rwe8g8q{)9lMZje8F_C~k=&>By z_<*pD+b=VDyUGjo88h1-IE0R1+J;1ad`{@B$g^YNJc!XSX#0?c3 zz_fybG}==kl|C_q*c#UQ`&0{pxT+dz5X!sjN`8v<{pcWTDqvscZzTCiK*H3b3PQcM zg!v0G6PgWVa&B&xUsi5uV=f?>czZK3LzC~~)L75bYWLXC*i83OXe!M*KOF~6B8oVQ znIL7gJAOY_&^)nBD5I;Yqg+#6-or+00}LS_vd@gjE|9r zOe*o$_Z(uECMf+KaXtQtxIer8-yp8H74jfTHd~t~o~PMH@mF*o?7$r8+&Nb>tn>?m zlky;73E5hagtyq;i>j?~?~n;IdX;%yq?sx5Sn?8}vbZT$8Kpc)VH!!5(r^I_6@@&( za7DkF5)w;fky1${mhdtN&N{BPrnV+e-uzX(%(hFfjtx)Sbx$rPt^*pMR87n^1}=hw zJ-@T9o}11dD_u!5DGlMc_N(jCY$!hLPnD;UhuOH_7NuGn;h$nef9U73^X!Ootw9b(aoV<*snu{Sl_W3B!6wvdFxrLB1=T9cS&F`~=lz}i{y^4;s{=mnLNrL9A3GLerhj-V)mr1ZRO3ty+dt(rsXKX_MQ z%snZU&gH0rYZG)@&%F)r^wKRZtXRmD7P1N2>Mqwjj!PwfdfqQIYcjvZ%iu0ubd~EY zSoBovn)^=7+o)Wf{9)-M*vT{42^knQCi6t)Yo)C*OILl$g2XZOu)9G+LrrK36TD+6 z5)3p_-@HKYV$P+xy&8CS73V|WaZXL};6~Q+ibz-RV2JO(0-nWR=A;+T7$U8b#h@${-KdW=$__ z*^utb%oT2j-q>WsLLq$Puc|le7IY3!bZ)s=@sG6(NR@O;SM1k*@NSAd=4DEJ_Ld~M zc<@g)r|*Q)NlB-z z6InSFc^uj6THtm?MZE$(lz>BmJ%apRIzt99_poeVI#hD8b4z^Vun8DF5>A9P|uCI=ZU|%b#_uv&cH3oW|P5+A-E#! z7P0vKR+=qJo(1#7gn4Ch9C1o!uwTMj2-ft`Nf41;-sa+6Q!*DOa!GI5_Tbm%ZDXzn1OGqYkPq} za`+3fpb0_jq7W?4c`_U0(D?xwHc`M1&Gs0vByh_JWeBM#6ow8DW z0os;;T4DiLtduL`(C3Nk;xH|e7?#J-X+&H^Iq{Tq1OdL#cjE)suShPaoH3O1@>R%f zVHz>_p*Ji^(v}}98Q~Z~*WIOw!F6(JygIX*dL)O^woNk7;(XER(}I{F!bjrG4JL%? zy{4Vvt!#hEQYqq%mJha4g5Z&bU4@86Ye^4`Q-kqT=g7cQfK3X7gxS#wB{E_rVnEcP z5u5{;dYM`Vu^yko^_{@)6Rc+ZP)=B#rbs0Ug!hmOnMMF003m=**gY_J3GwKA2%L@g zA~QAjVH^+wgaF-N9=!)46yB1}u@Q+aMXWr9Otp@2VuYnadvwIP;>6U%KT$%pNZlev zGgf!9B5cbj=L(OQL+EOU_?)Ok`pO_KI>rkK8G~NV*(`6~Ujz%9(OQ>h|L8W=?3-=Y z3D|W8TUv4FH!DAZI)cWuQwC$!&!|sL>ex#Uz382@lVdGo_vA*q-a1KhD_OB85vaZM z$voyT4*BI54WH?gPR{d7oA}(@`h{T4zDD5`iSPy+8fQjZaPfacyIRvmZA(9su343i zIFn&$)Ox2NB%-$Dq@A`TigZP)R+y(E1Z$H5%xZ$% z-XLNd&eidTvCm1*q8ZMqlhRh8GnpH5E4_q?6}R+KM4QqXZG%Fl=%d$>gGP}We};!G zVm?Y?fbtxyq5@}o<#{EZWckLWQ02J_OGiV9e2Gzl%6GV!aKDN z&qV6WCSPanAd*=9l$XyMJ~l$%+oFMesnBuX>aW|`T|w^T=Ui*-D44Zgk^09)<$c_# zL(G0l3sS(BjFysw5s$;=eGJ~K-SAk*r{ZeD`m5Od${ALn24Ae z8+n`>tU0kVurM&NQsav|orwdVVzoroIeVnz$ad3H2{A`Fo8%nYk ze8c3c5#M`ahk+Mk_SU7liYuHKKf2)*xVl9x=8N;>m0O^!l&JlSI~?q`$@)~&-8WHC zq%*Dunp~{Sy)u_!R(4C(^kx8Y=@GD>CIEGxdsIP_R@JWq7Rp?$IOo+^p%^ijtELAM zoW$R?=R`RYV=E}d;uW(FkBec}=W7k=h<|X;ql{F$i6~u-@}d_lE1_{FJRE!M5dJs0be`u+E3{lGkB9S3futafRQ|!cL*F8e$f*4ECzm71D&Pw5D8dwzqm++cW$2 zO0WXyk-(NW{ZjA>O0Rij>Y2h&Zzm>7OUZwVs?mX_&Q^+yYn^OQn4X%MF*Yv1)_^l1 z;hRfP5p-f@QHv*JgnU5ZSS2vVGj=S|sQ@$txI0k(MMgp}0HnF#RR~;)QNuvMY@>AR zrZ=3&M~pMyH-=K5R0dWpo~VUG!vPC-nNC%;oBX3$&2%lRmdVUNsUii^iplCMW2@A}W5~5)TA$+c8(vG{o*tiFzWl=wrH>v8*@X zrf5*z@m3;UNB2s_IAeezD`aI#gJqK#AsW9JEx#1?FPO9GHBh6?rolDF<}4%ACl;5? zoM)Pn1?xHZt&0oQ^oHOw#@f}S4{|Tl)yZ+yTDYn=jV5-;X_|{xE$(!vhF?)(`U<@sqLVj{E(NCZ;+^*B^TOTtJ>l zrU@C0Gfhlg7s8(?k|l~hTL{P19_2sciPN2VHGCiM#>4eCOkrM=JJe!-6?*LH$s@Xy zJlSmvEgUCuFXqJM~i{>FZ&OpjGfI|F|~77eF`@X_53r|K)@3*#GnHd+;QF)@)AiC1gR(YM|Q zSm}M#XvXKtuiPgP98=)F2m`(ri1eroN%SrTCj*-TRQ?Jfua3`LF}UD3toGGv3i*(f zqH2^9yfXq!q#8{bS$WyhfTO5f{2Eph%xKR)e&24J>Q1ItXKWrnN zG^REU?p%U=0j5RTV6^PoX~S75|9;9`tUQaAJDPmA>iRfS$YyG$1F75PRjTl1aL3x? z_2x*nLv}Te+~}N9zX`M29@wSNSB5yksBQ83I)9Z;V3u3LJJvo+-P-y@XbdBiqc1Et z2oljU2cdk*&24qQySNFAcN){YV(T)}b(b#nG=P^M=U^?pLh&QM?;v@f}Fz-hp(woUh~Cc-fp><-T|DEU~R!jK!ky zUDb#oj2k4kv4#({Ap;)%)<9{UP(m&}1B(ov5&R~NbTLKu0Z8^FS;4GDTFAI?4~Hai z>jex!gAfT~wCQI@BGfXhgtEn;FA}0<3QUPkk%}TZ4>(P+mTjpcuds!2!tKW-X;O7g z$+{Xl)b|GN#$(dc7u1FD!d_JhO<%oD<3yd^;F#E6V`Y{_>E29R z<`kVbQuRjRa>#h3K?=w!iXGBHFm@7cc-X=)}#)z(iUJqq~oc=vcd zX1t$llf`j46X9?@rZ%~cj40nHhy@}CV3B+o1J}o!?aia&knYtOnrW8X&VY&)<4d=}_a1|6-UKqQ)?&;K{_APq2G2nXy z?&`RZhUOpJ2?@fAotNfZMV?x7?AcmxB!67`DEI`QtT$obKM|mU_B`0M+TI&#BZ@TJ zq2|t$3!*{X&vRT+ZUU!DQhYXH4Y0^Z<8;)f!`yh*^Q9v6SZgNiU&CR zNlo9<#MnBY)n8>6%pyj+Xxp=$BBTb5&^87kXuBy1i9V^V`NorTLtCB>7K9QA)9~vi z>jKYjQROUeyB4I(p;jRy$b?T4+_)-w`CR}eLT^#W%q&8lay9Z$U&TTF$$}2f7^k!aE6~1?FNAc0bj>LA2n*2kLXxyYh=c2xd-w1JyBr za20X|Aq-p|=RWI$QI+R&90Z^O*WlUqMD9yIu4kQ&zN#UNs9hYa-Ax7R6)QDl83F~a4TDOPv4M%(=`pb?*~6-uuiLh0%P zUk14Msxl|UY9@`yQ##%oS!CD?Z;wi#1dV0&Bw}4ct;F1gL2|K#T&p3^X)P>HCE{S| ztE{sJrIzMu{qwIr#tp z3RyP@@E8jBZ-{tPsCfFoS?ZSvU@0$$9{a$pB`R8PM(5%Skyy!xM3(qP%ezW8axgNb-y}ZXt`g>hS!Y zv^EpaR@j%_Xrt-<_`>|i+)x!K+GI^-;k45D=f(F*V@$cJ_I5AI%Xmk$dBsdbo%pQG zjhB&uFpQ_fjiuV7X*9u93AtJ)!#*N#)A=v=nwsa_r;gSym==|Os|SjJEHTg8CU5h@ z7$z{gPQr=H<-4?tv#z$E4A7prak#1$b*j)vqgPzwa21!GEqPorJ>*2lrn~VIoz`1> zA9=cu5=jCH*=pVld&~mBV}6i3JhzGS1{1#V5Sr^YTK%I%YPdJ*;)T|2%%SFyF0Fw~)!$~0@k*3KgNC{Sw zc>}hNNkuep(QsgeqwbvJokxfN!K2Yj-e^>G>W5xK1R9W)_q6%A?e;YJcBBjTRwY3g z?sSHHgBE-uFAIJcr$HNa1DHF7Fw;S99X9S80s#$cSAcB?HWr{vnfY23feW5&D$#5U z>~20NnCmKAl5ebrIBjTaqFx*4-B#8@q!@8nSC^VF79{oSN|yscJJ)gzIQj>nRwRdN z8=)?Hrl)ZJ)1+)#y%D)VL==TNK#vx+F1&V=6`F1jlsm$W&CFcsI>Ee_Tp8m4!L8Lv zGgAHE3_jc{XcvqHaWdS~mya5DfW*KIMXKp$PKrAtZjNAM@Tn>feSqeC#*La~qq=*+ zIf?+%WCr{!QQMN1IYdi^(X^HOYHactS$kIqoz*H~X%bg-6-3BWh2KjUA1jY%FivV< ztlilf24$zvFUaX>UR4rRk^5$9ygjsp`JHquo+ECI4ktq`?HKjsY%DhH(W|vN*9Ng* zELNu_ugm6T*sGc>n`=&+4X_Wo^k&R}WL8m*PI^4ntgyib5i=Cz)*wSM+&Wk-M$U_K zwt&07J_os$$ykecUM!9-ovN%0-)a;DMvD*xAJcPBx~&GyXnBQQiYP0Wi*h>n69-aR zAKO^Go6&_V)2h*N5|fT8^Qp~9Ni=hB2-T%15XY=_@0LDmGA*_dHen(#J>pPm)(FCd zPB%YY?jnwIi1mOzvYify8{B~d_*`97WboFOF6>(7XzH6{aX=;oGtEPb*k0FF3_uay zj6|FKBA8k5ShF8+l*9!8wBxKOaf@P7|U zA9}ur{H2coMs4ZLzn+yc{fCj1<^MO53jTXHF!@h6Fxa~rI9XgNjw6Kt3Ju?#-W62Y z4k5N^7p$5e`K)_?C!rP@RyFj&vEu4+7%%5)qbAt=(+}ik^N}~{@L?? z3#1L2*6$~!7+K$pOM)qVfg zvBrh9XX4c6rb1uz7$o_y%%{=Rnp+y zuyA}dIoUVZYqpOsM3OdEA#v2kj*j5&ca|H_%F!h6)}nN}0w&L^$^98n5;QsNTER>6 zxi(JqcC#0sHMvX7XR*3rZz2wnui>SXD*Q9@>U|;`FHMsbdYno_aD=vGP>m({8Cij3 zTO@8cyuN15d=3Zhs10px4{&8>zS}O=L%VQ_KU4s08%@5=0}_CsD-?PB#O z8ke0c&Kf6iJCQJFLp2UE%Sft*aC7U50tS=QzEnK#7p>dMcDz$$nu9@B>L^V58K!pM zLDcc70xEhYr9lA#fzQsG-juiAYl0AFVP@*5KOO}}q1DfW(tM1*?MC$-HXCBCq+n>H zp-x4b106!;|;=HC;CAV%jg+rI?@E%LG=WcKU2QtF<(TR8;9x z?JCqh0dk9dp^P894QXh*-}|yoi*;W2DCx4(hlFC^6DykuPM8Kh#v>)j4w2~_ztk^; z<`kB>(B)MZuUDoE0QKZ{>oAqCtKHE(Uz&Uoh|gW68yG%B9G86n8sGSzJUjT8*s&fl>+cAwt}7VV?1_aow^UVwc^ zbYVOw)d2(Wus5)O-&xz2j_2zFZcbkB;~~1Zk(<)|Vy2PPMY(*xYF}4(Uyqio^V`se zZ7swwkYhu*&B^Z51~mdo(z;atIEoV$2T4x8q;U%H*`N-Vb|wDa%7L9}dhVP%oaWwh zB|q+M?o_Oh7@t{xjYuo!yceh#O>^w z9`67M5UYvWWR#m2RHnYJA#0QsM<{R0NRtpylSwr!i0=`r=XLA25RHq>#0FLkiXU{2 z#byG!j!}hc7X*BEy2GSsAEXDRv(xi*#;ah8^@@~eobG&Lf}yqg@k;IHigMINTK-yd zYA@^+YFFGXHVYt~TN=rF8V}&rClkN;43Oh}jtna&f+!Fb^B7GIj}={Z0SuIzr4Dch zvc(B0x}xs`F<{4pismao{*@Kozh1NwCKnpapPpQx6s9pqAA*JJ^Bf{DQajLs!pCQG z+`=}R#7{hxCh(@Q)GYaTYsE>BeWZj?&`KPO<=<3UR;o)L>>cP+`v0H`GOM{A-cMioNz=QyJcuXM)%6(uc zq7Wh**OG~VHx$ju0u&^llT{QvO+c+q5XOQ)GU1lMP@VM(3nE6NR#Z+i8jwoJP2V3+ zicm9;Xb}wfVAw8;u`uIR8dOGt=*c|HEGD~+EAOkDM%U;RhkA-2Bo1AbklU|VTXm(H zf2>yTOX?t}fWHicswqiZc5GypS^NPw0nnB_JNGZGQ{Twb|ykzKDE&i*p zuGWquUs?{sJ_wtB^40D@6-_x<+k&Xt{f6G5;75BL&V;&aNg%{DxH#6MG=F?q%QXSJ zFS43ZW@!l%Qf^fePInS+GZJpm01l^8Lwz5C;Bq=M<1d)o;lTMbrm{^ia5+C`pqO(l z1=nk(f_AbiOl|?54el3z)uDocIN+I1yXP#I;<7VB=?U>gC!4r<1auPHFYa{;gT41k zZ1z##T^868CFZ(942{RV1od59tZ*A*IU~yYE(7#D4Uc%c29F-(J<9H zjdSMxRg5lA@-8N(JhkR-bNoafWNVQyM+z$VR{dk*X*o`&wl#Moqv$O+tmnMn;wj=< z>gRi-sQI!a3(54s?{Jcn2*AsMXh;X3OIaS^Eav&q=-Ks1?9gsK)Ju{8>W`XV*ZUPT zD&hb_ymEfX3kV>f9$x@P%54Oy@2t$!03E9UKB6z<6@twog`XIcp1M+v4vs9x4z-k# zmikFzPV7THr1*~sehvK+Rm~YdZ=76gnfH=bB1jv%Uf0A=eXY6?sf=A)S!CIxedVX_ z;&or5sMYZGECKFAlqpgWs7gHk2zW3fsNVdA0{2qJ_(^Gb8o(U%rLaRb;i6g{TJU{d z%Zxk=q%N_a^ngL()DX5n=e1pt7Soxe*pe|1jx(D;P@MFG5zOwi{=02 zt&0Cy*4UZQcivL}lebWWN|gWicuOWoEa)$NyyD~u%zk&p^1n0JAL&cx|1fXy0Hgh@ z^rhtWVDE=0wkfJ%>Lmb_`##d_xa_fR2!#9oDn2#w5#uwYN)V7J^(@6kGs=1F#S+!-O`L-P z4kHB^*D|Btl^+7R4K>MWmt-5_-F;BLnQwlHy7a)ZgKS(k$G7`2` z2RrtHom|2?V|KcMAH@x1J#~x1Ppx+k74!``K_3#D%BKMuI>v;J*?cA7kHn4`i)ixw zWTtFtd~7IKQp2wToB&*Q8R$UZEq-cwl7%uGX5=RXaQpstUaLOweLlz?ut z{EV2&_oaIi=P!56ch9jkh+n-0%>TK;!t>9;qQH(n_Ej}QPctE7BrQovGvjMAFst$x z>V^__Ccfx-#YyQ&U#c#2(r#1p3bO*UAy{MyYRL)x@@o3eY)l3tbo&=F(yAA5s-c?` zlGIWll#^1!bcl8`6T{TxvMP4c!*t}s)Z-|CQmBdhiN^aqG+T_!b4*iA%=4_wn;>Cm z$;A7p7no@p=;>G~7^xbVnkh_m{pp7!e{A8X;;Uo~lf%LJ#l7UsAvcZ9Wh59jz2vR- zA$F|3Bq-C8EpEmSu=lyL{oYEb_vnJ7iJ7&D zjgzAu(|_l=pHTQmZb5OZySqEF?1s#Y;yd=isiK(hgcxcwJ*HzVgB>G303TJ1J}4A@ zKUNL}^Y#UWjO@5n19MQB3CPwDa{y|;qFIcJ42pGlnN?&P!de?cY37hL^FUG?fyOXZ zd8EkczRF?NX;jNR$h2mjZ={@pJ+FVHrOEY69?sq1|0w2tN96s>_&uWj$HkvNeiq~E zVBus!Yh`Qn@sDCM-opbwAAgCd%S!?Gk_A&i++vfbtKmzhC0-JG#G0!M+<{^#0u6{hKBJwp015mOss(T7SF5-&c^o zYO%8aq4oDm{CyGitJEiscd0*@RDZ9;-&ZWZYUyzPsr9!@{Qa}+SFPyxG}Qaw_4iBs zeV+d+wZH@L+jReTW&T$q^;f-oUVz^Q?7QB-9Il{XKgTBG`?t>f;_l%6SpWe44?#AO AHvj+t literal 0 HcmV?d00001 diff --git a/lucene/backward-codecs/src/test/org/apache/lucene/backward_index/sorted.9.6.0.zip b/lucene/backward-codecs/src/test/org/apache/lucene/backward_index/sorted.9.6.0.zip new file mode 100644 index 0000000000000000000000000000000000000000..f3af2e4011ee32ccf1caf5fe2363c9b6332ffe82 GIT binary patch literal 142393 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 literal 0 HcmV?d00001 diff --git a/lucene/classification/src/java/org/apache/lucene/classification/utils/NearestFuzzyQuery.java b/lucene/classification/src/java/org/apache/lucene/classification/utils/NearestFuzzyQuery.java index c020d7487cb3..12d11e59b9d7 100644 --- a/lucene/classification/src/java/org/apache/lucene/classification/utils/NearestFuzzyQuery.java +++ b/lucene/classification/src/java/org/apache/lucene/classification/utils/NearestFuzzyQuery.java @@ -35,6 +35,7 @@ import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.BoostQuery; import org.apache.lucene.search.FuzzyTermsEnum; +import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.TermQuery; @@ -214,7 +215,8 @@ private Query newTermQuery(IndexReader reader, Term term) throws IOException { } @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + IndexReader reader = indexSearcher.getIndexReader(); ScoreTermQueue q = new ScoreTermQueue(MAX_NUM_TERMS); // load up the list of possible terms for (FieldVals f : fieldVals) { diff --git a/lucene/core/src/generated/jdk/README.md b/lucene/core/src/generated/jdk/README.md index 371bbebf8518..48a014b992b8 100644 --- a/lucene/core/src/generated/jdk/README.md +++ b/lucene/core/src/generated/jdk/README.md @@ -40,4 +40,4 @@ to point the Lucene build system to missing JDK versions. The regeneration task a warning if a specific JDK is missing, leaving the already existing `.apijar` file untouched. -The extraction is done with the ASM library, see `ExtractForeignAPI.java` source code. +The extraction is done with the ASM library, see `ExtractJdkApis.java` source code. diff --git a/lucene/core/src/generated/jdk/jdk19.apijar b/lucene/core/src/generated/jdk/jdk19.apijar new file mode 100644 index 0000000000000000000000000000000000000000..4a04f1440e4a413b27a65d8a9af993bb90af6f56 GIT binary patch literal 19164 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 literal 0 HcmV?d00001 diff --git a/lucene/core/src/generated/jdk/jdk20.apijar b/lucene/core/src/generated/jdk/jdk20.apijar new file mode 100644 index 0000000000000000000000000000000000000000..942ddef057b7dcc70997d162e44ddc49a908fabd GIT binary patch literal 58749 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 bnftFA_YAO91_ELQ{J^6E0lgi0`t<(+;Gb~` literal 0 HcmV?d00001 diff --git a/lucene/core/src/generated/jdk/jdk21.apijar b/lucene/core/src/generated/jdk/jdk21.apijar new file mode 100644 index 0000000000000000000000000000000000000000..3ded0aaaed4e437c1a238e787ea31dd3979799f1 GIT binary patch literal 17245 zcmbt*1yCJG(=F~0oQnl_cPDs&;7)+x?wa6EAh^4`JHdiOaCg56A-D&Z2fN?@Z^E+K z@4YurR8bVCZ_SxL-P7G8_X->W9Rvmj1_T6zNa_B^|1L5RSP(N^CtU^$T`OY-BWpWD zQ)4RzK?4IjLwkEEU1w`Y2YP)AU3+_FB}foZuf!4E(3lm42?6w;R#6K30!Thc=gO6x>cJ`KP2=Av+o^&<4PYb0NT9t;Akk%J+~~5FpXh z;ByrZo*Z1PCbc|+R5?PwewUVuJFPoyx4yI}FMI4D)dRcZzrUR^z{OpoUj+s&+9yUP zpEmT~90Pw%o&OaN+1ux68}Bg|p+BJUFjQ~{r6WpS>6&I;5Q?}Lvdy6+DsefASu9e< zm1>F%#J=HRP+_r`eA%g(k2>6cvfUrVG2?g;H@39p*kY$Ndy=)TOR2~co2-4hGqYUH zJX1>FH2G#(6LDf7Y3Rn+k>9YVFdFEr zd1SRVVhEgT8dHWNS{2Y~b}LuJigibP+&BBH^i6N)mUNa*Dqa20__^`6j~2n6L+}|9 zfR)hk9?kc}%{cO&;^;I5zMyjB89Y+{dWgA=8cwru4J!8v8io{d@!JF_2*@S`2#DN2 z9vA$lkBgn5mF}Zs;waxI115;<-p$;ZM@(N(PYQ*~i6Z-)7lmF@6Nz-$H6RUT+#z{y ztV{cN75ZGhM~{%n?@;cBdP#ZzQ_=11#Wk2ssJ)Oq`Ld`sEdCjZ{x{a?8}HcH=Y&Ex z`-fBseT;{Z6q;6bA%?v1+}M2>bPhY!+ahbL)+3so#8Bv*Bge^#!??QV6k{e*P1>V3+>97o4%Li zq`=R-q}1wg_pTWxS(95mko%IpZm5TaINU$00lbBKra+391&a>zl2hgog05u*7&8K; z?_b$p>5o78iFufl!AAQV)*o!-B5iWtvmpcaJ2t4FWJAo+O5efM+DgRGUf<5t#=+X| z5jCYzg0dZqc-`8zK8i{rf_%=0j519LCO%9|Ok#sDK{yO)TPhhayW@_eczl2>$bc)l^r2Zt<84G^WNS>3>T5cDWM-oXZiDc2tV zOvc=iOu5w>a2j#({Oxf65si10F8h*goKt+Q101O+w)mi|T0BDM|!NQaB8xw%paNh?b+=>X^I?;+SVwkW&C4s&{+={z(>1})sN^r4{mHLy{ z^#wVN@6C#?I2m`K%?k2e5)RrJ9+<)jex@jK&r~@0@0cQalBt(=){Zt$i)_@8Oosrv z|A=VLwVB|@q=MwCEg@7aHu8EVCS@$%cAXyXoQWh|>doSY1JHMrUo3-A{9%e&&IWH} z?4o$I-Q2+HJD7k5#LNB!!K6pp3M9%g=Woe}mW3ko6CDL0&WyjA@3!qPo0!L0dUkH2Z9763VYV$r=AP9eXSva)gchoU_AWIEpf29g|8K)4b}pF7P~*_q&CNU zg#&ZS>$)xrWu6!Y)SRF?RVR>7)sGDHD%b^yCsHxsgB8yAdybF$KspG z732!kB-bs8(h)L$97x`2mYsM`cBlF7c0eB+GlDVfkMVQG5LXq^;n|+uj#)0JuPg~! zLD)pl4LoSWY6*J6Z2CBAp~Ac? zx?8=&R}CmOja(z}uD*-+dL8JVXfnfY6e9wL#LOZ3mK!M~&AHz6jGHLG=UuiQhKU6# zHpN750>>OA%6wd$ZHT5y8KV;(PDUsnC|9qr3q}USfSd3wXuljNC~k?%b=h$3JclKu zN~?(*txoDTp2bo1VA1EVS*kvCWyhvBNDn^p1{UJf?w&@y-}=bYsmPx+lFHgVNZKPI z3so490b@ev6HQ@m={`dvFtK6l@uyY8M*T`!03V90iUEh&gS3f``l4Oi4)_pcXpot{ znv-v)EHBs(e`?s>UO0yLB0dG!NsnQ?A#~_0elJ!Oa7r!tF{e+vt`v?9T0a3hihe(- z%8W}45a$_f7s8C5TpO2P6Dt(~)hl7`*`yw%+Gk5(9 zQlELe=z>!SZ7^YdRfl94>`|~WHWJ$9#aOMp78zKWDbyK@fz4&iTB&>J^?P=%VR`dI z+Ro(z)R?^hy3N#At_0J=er1qRZXFd}(6F=_^Gn}QmCMBDZnL6dlahS3>Z+ZdurIy^SG?xmR z_=7=LL_nL_j-qx}^9 zSp2H}sJI8X>DQ^=5Nc*EQkS~P?lyxzuX(U-EN?CPzDg9udXAKk=~vSYK>r>rkS^3vW>i;J|ba= z;RXoT6;kc)1j9MIVy}mV4_ex*YuSrP*XO+Wth1*9owq9qY+Ag)Kn*6bG;eb$-P;(& z&TE9&6lX!W!|bbY=&zo1nQ)@R2S;%4`#>~7Y>;4?XVLV2**hb|aH{%^?TnpB1dYqG zpxR8NWwAL$Vc0Rk>ymu%w_!Py3+WKT<&i5o;tkDW!L}sYN-1*lVd_P%7P8&ol&->X z2fEiY4L29|-T<+KuK4Gx8gsqid(xxa4$s90+E_ zM-6SyA}X*S$Qn6E4$%A_VEwU((tmUA-SM?Fc z9NalKz0=Zgf3>XYOlRB!=eWLn2b|Yp7P3nF046+Et1GH;K=Cp?@9H#@09#5Yq9q_r zRv`P6E?p=}h+fDw3(&bR_=Qre)ge$7vCBG^>mZU={lH*S{PayT0Oo| z#mX-{$XJTYoKFVfn?s+Vb_jPH_X$5NRDH1eH>j-{Rfg(nuNQZt4$S$_K|NwBX&W<` zw%AR-r#P)kEgWB-UW2XTk@-Z^<1$a^cQ7rCe=j2$#9fZR?bRc}E;`~L4f+78qcuEFH+9LG4;Xq-4d*3ZXh$bEU* zewuRu+2<<$IXu|&4X4E;fhofb1RpM19bSZ-N^fcWP+OXgT|h8FJsQx;&wh4dJ99d} z!Y^c0)ttdSma{d%0MML8!xGGh@ z@I(_u_XN+~1f}c+`WK)}fxuFKcrCIpDXy0(36V+IXi2{N#fW3isz~{uW&i5_TfBK> zS{%#CiYgh=CXoKmkfUZ{}m>0`hvcd z9R-8StwC5gMgwk7AQSfwPE(ULMuP4wH!<_%g3~pzPpIKzU}9MK!z*buOA%LP-zMjH z>XnnSBB|n1(lUka3}9*j*+16Jn6?ZipKsP}F|b)(FukVy(QPe;^)V+M_slJ44PA_h zjB$Q3%0EQ>L_rLGZA9fJAAiK>)^1Z9uGC0p)c&)cL*t;=`OrpG+zE8^QJ`;9YIi|4 zIn!3+9HA>+{vdRzL^<9xygO31GKE3U#^M~99cgAH9%YlfV#)}mRS_WjxtP}HT5PT9 z53(cn_20y-7<6h(`W4I%gULe>O5;(c48$~ER}k|sG20Vm?*;hJ;Ye9iC@$zGV>?cF zPwPc$VXHTY^eAYX(6MB3k+8(~4Ne+}#n&H#spPU0L`9_wEz;Z0gr_f4!Nir4 z&SBb|zydeLWBG^GeNslr#opKf$A^ca+GQL{<&wE9Hqr34sKUXftZ^Y}T@Yfv9iJW| zC+j1btl)-yal)X4SEjK2412JHAaX31e6eu#0)zwRg5b&qC7flp`XvQ6ops1jp6$Dl zGxC7Q02G9y6n74+Pbh16uIR1PJ=Jr0Evtt3@5H*i-%T@0P_Ry*aU4yD8ZsqH@_#03 zwX*3iIC5?mtR`2C`)c#z^HLkqE^K7=O{381#bT`sE}R-=Q??#7sbU&#OzN zsl&Xrklsb_5P85+7^u@cC4%h`2)6RdYzp2ItH9@6lQF=vGe7?UTdTP*1I8DV5_ohk z`8fSQ>h)X5vC5AlmCF?`$GsCi%<4!ykshQe7%vMYVBFF=PzY#FA!5+)eT91zGR$!R zCG{@#&2C!g4e2ReHvZ7r&JKlRY9t0mh%BEf#RrK2$4{eCEc|q*rag`pswpMm>}M`t ztXN@+5<#(#ubG$t(k}(sz2zCThZTHN0fi^<99TFN+17ybHrv`l$lD4V9d6sIpcwfb z6fQC;-0&6)Vq;b@bRLQjT%=YDV*Qh_sAQ%P?xdJGk$Fn9ZW&x74W#K3P8mevpx!E? zq0ct#OgfWlY?oe)o~5Vr*h7BvJ&cK@rr-m+Q z4Y7G?h`}-GcSq1F-^ZT!x^AvFHa|P^z$qJmCM3ww$XO<8RQ_VwA0|oy_cE6u_(*ac z6<$Eh^NTudRVP}z#a+rC-y zO{<`@f*&N3`;<#Ghy4C$G;UtcW6qKJN)Ax`!>Qe*fM4O#<<4_Xj?ww(4zXP@XC+3) zj#0HUurOM34h;RvDczKT=5X5a=K;M`2huLZMETamwQuuEnOx$RlPgd8-7|ph1wi*4 zpnD0>Jqzew1a!{>x|adnGlA}fK=)jrdnwR88|YpPbk7I6mjiDY^-Ht*>_wv|K9GAV zOW#r_T`RLW7MqzVO|3QD|3NwW`v>w7W$84UBwkfE=Q5Kc%|HL(=#o}h?vayDdMnjh zkankB{mdh|(&^a^y>W;3xhuj%g>Pd4Zaqvr;2pIM>;da4^D5k`%i)>DD)p)v zcX;Chk11klu4Ba4HV7MV8xk8dM%ZSUcT6_$2MVhytKZsayg#)Sdo6g+w7ntN$@L2M zo&k#oDF>$qH}azKo&g_$*n=notNW_u1lrxov~Uo&d-q4xkR}Pl4IUZ zxFd6_b1yfgm})BGT;1T*sh#AD+lxjJH9bi+^dforLI+HIscz@IY%Ko7Ef(NTSEGlx z!tpSwNWyLAf_u9u9S~)m1CA8RPjE&kqQRZ|xJT>Fc|8dXzh}WXsuA$`?o=86{H0-d zrE?QGyPr-ro2qSLiDCS)_T03&zPaE=X1G&x%P|u~N*LoFYg?DQOTE3TUmQk+Uf|U* zM(aZ|Vofddyz9Q?j(VSv{Bv#f>10Gs*TBHk%J|7E63-9o8Ga}zD0?VSF{q1@t}2n6 zl&)rno0{va$-xue8?UaIn89X;^sfHvaa1QLF)=7mKjOQbl1YOMN){4dygZea$;Im| z$pje{F{rSk!6<~*u0~N!VhRQS?OQO?`Arix31U1X_d;1dBFGJ$+pR z9phCU9gy)91Wlc!WbgOhf^8_`$3CVqQ2dNT!)?zd+aGoZ8m7wHTzvd~x0ZgpTa-_p zssEfNK?@6OecdN2pK)4>XiVq~JmqUdm#*9BQHjUKVY^RJ;khb^8^*O)d{ zkPhy}RmR`aFxOT74U%GPg_fa@16td{h%8Hca_&afgu_ zXJISRY0M1$VVxP|CIhdDhmEM(sL%)C@Z2HhB{mdK6kwc!rLKMfwXw~}y%rw^-WMU- zSnM^xNW2>eRdhj~pNbu-(81Jcp&;2%$V+YS-#(5OkeHJrRL}Gk!F_Brqrb73GgnGP zIV-5$Oj44ab}>u^Eev}-N?}^bd?7b9Rd3@(3cmSBB($08=pm%E@>Q4N5Qax%&ZL$3 zO2D)`7T!0ZZ)%(T?n8F?GW?Y^=k>?*)6HKm`Yfw2`c$yTH zvOykSJjDyVs?10&&{HrzAC2G|`D&SsAEv3!RF&JF*CkT~Q18oV=>3L4l8lSzX)^dB zk_Ax(ho@T4K-xD}Y`O&CY~MMXj6q_*-n8j>tB#{?O()-NV!Ih4KWmX^g3htkBopf~ ze5WM@;7?oLP}i=#vt}XXui6i4JpLr?T0oe4a72IR4rGyXv+Qe|L(>S`A9Y^KQ38Fo z&(6Oj=Q0|6z=jlX)jJxf`y4*$87qMq|F~O8;*?v~Ma(&P@VmSVO?!!B|MjZ%59_Z| z@2I~JTkv@zo&>lFAA>e`HwEsKoD#lF7fsSQX-U9oL#EgDdzZ*5)-2g9)-2O3*eua3 znnJovv`n^4GOUAXpU_6VnOk5*aPUX{ll5@wOUeD^QyK1e!a@EIu3+nEXr*uXq;iBt zNz2|VYrqN$#F}t$I*0zXB$q9d%c@@wyda;=NljE{OpQiiaNf(iIA~9=7yX=cfKt}H z{I|wVX>X0muMRIxkygQ6{d|L5R4ipp^ZDR}obZ>PA2{^5^txj}vM55Kl%y9my@!29 zra`#FP|dLet$QL}hKjROIWj+}=qKDXbw{v`yam5OonWd9=TuC=*IaMpmfFZ!>8ftE z3EEYTcQm2K#|)fo83_vEHAFD)ur>PpN`TC2U*+Pcx8VjJkT5zWLlOUy?lj`-VjlL( z_()(G#nj=fU-nMW-OfI(F*sF;h?*dZU(|J|nY@Y@9ARUCSr*%*sP!!NO=2R!>#{ccG1~V&)P!D+S=UF=21eBtEgqIAc)NOib~bO-2A45 zpp@A1V6*3Z6}%@W3J^q?N7}-`7*9{zWbl>&)^q63qZ{~f^h3Y~`PtrJUt(f4OVdh= z=LOsBz0*dOm!|5-T+xsm~~WZOc9rTL=ZX#1=4kY?ud4lMcT3 z9p^^aHPpG>qPFPP@AR#Ka>$%-Dq<36iMplXzSo_-NlGKv9`@60B6Y%G>u~h$NMSgz z8^vV~{Z>%|4=RnL&S4pSM*EQ;XZr}-Ik}OZE#|xLE=)=Z7C={3$Cc}K#_2OQhLj|7 zQzMEctl3XsaBFCWE?}|!3JVMER1@X=>B6RR+*YCA?N?7d)uJyO53f>~`)*JY<=i{x z?51IxOG{SiM_6eNjKR*NH0DU+hYFR{N!D|03#-FWht3$wBue{g``%$p8aRD-s@dY) z%u_#I|3F?s`F5+f*RkuP$2XS#o}h7b&nVz^D>LQ-LVpA|DktYFX*rV1lIATFZnhpM zuH>libyJ~4suSa`dT+N$F52|BB95;=*!Akyu^)rIwZXc+oE-o@*Eq9nb3%D`5b-JB z0_&aU37Tt2C&ug;h6Om;ZG62LipK1^8_N1N)Ts@Nb{Acp)p44r<T zzzTT^y!Sxc-*%#(?x-nS-FFH8-2vzR?tr7sgV(&j_#f*3_@7GXp6Ep`Bx7hv2m;=> zL^5oTpoYQ_gdQAzm>=zAqJMhdyWP4!(xiLu8F5M~p^{@0ArA8tEP6?e87wjhMj5 zsebQ**qi`>7b^ugR>Hc`s;&;Q4a9h}PExe@GpTBp1L1DSj4wWNwnP~c2!FU9PE~Zs zw|mz!|E=piy?rXW7LHE`jMz9WRb1u!%xMBMAY7?4KdUYd%<}b%EXdcf^V|_2?WTFC z0+rPGy&##LA?B!CU&b{&qp)s4JYxpVb`t#xb-ALGcX)ZOmW=o9Pq}D3?~cD~gFFX{ z0DFRt=c!!6Je7D6gg)A?VZFuMAFNF|UM(>cpju-P+POhH^I9&3<7o09S)3r`wWhg3 z-@CRxQopJ|PuX=X0~OX~r<;bmCIR<_vp0<_ezRKPrR$$qGx}kqZ5!KeI?OjB)7qHQ z;oB@MVu(SYCcky%1(SbMVWi+{LzuOW5D+MFqg)C6xH$UuJ{nVGN~lM3SHF3-WK?Z; zS!}$D?=PfM>P_XpZA~hdu&-;lq*1d24JV9MGD;w59omJ9Y}ibeOQs3ui@#SY<*p__ zu1-}wq>u;Y@Be(fFG1u24z3gSy$?!shwpP{JE3ehf>+T@)F*vs%SltJl#-{3tP4h_ zD#F%7{d~bkbmGTk>L!u!cpCLM8P(huQwbh}Z zxN;w*JUd~PWNcQ05(-70Vw$1qOjS(&_bkQbBE#gw{^-tp3pE2WSJ$~O>sShoW1xzh zsObmGPE$41=2LbOx+T@+68q=fJ!DJSyP=!I85;Y;grCTk(1PZpZ(9gUn%n^7@P~5e zp&14FJ<}ea+FRLPe|AEzQLCpVH%vO|*~Ghk?I^>wKjH7t?S~dH>^x^LtJPZj)o(jY zd*1OApf5!v)IW@=l0=lWWe z+11$`EWRwX4RnJ_paMxth^PT z1AOf3EN&da>^xhlm@Bt|oN430bd~}#wXA!VQ}MPdR<5+6H-%tSlErkF=}GT!Q|oaY zl&Zmxbg6vhbt-XvzTFb+m|R(gxm_p1;UKMx%LB4|b}qO>?~!wZ&u|cZFmmoc^_=Mv z?zEQy80bj=EwG$Z8ocCBb4rFpcAAjxsROb9g|B%8!+LZ%2miY@!Ra%-B)4Q$}TXY?62p??r zY;FPN>?Uuw3g=ghRvcsF2^%OWW3;B)uZF_sbZ?m0n#6n0Ld}ZovlzJ8xLxU5s2h-R zQtTg~4(7fgY%^~DA}KCn5F_Rp1}~u}mP_^*$EzT7aa6#B8QUO=fd>GYRGao4sp zlLaTc%sR(B$jY#s=^H&Y1l5WpWb5K-DCK-}c_|`kv7KmjVgv+qk1{&^(npg9%XQS0 z_t`K5Ozty;c%}(Q>D?HcjF&wzX4~aMl*5OfP;!mCeU{oR3%1b0D$aV)`Z?KD?{TAZ zw}lwbd=y9Y(_FNr*ZW?5j)wICd?6Gsu#Wps93SW`po`f6a!d)K)&&+(Ty&-9g-r{Y z&~4`>TH<#x#n^&*G#zV?fV)LY8B!?uTIhWk`uGP8xT+x82PR=W4d{&S!{6p_I~Pxn z{ybvR+2L_TB{ljF8UyYGb2PuLYcZjy$0%c&NOd7LqWD%Y+P>)b>UJ`l7wmi(D{-Uz zYHHerOgtrhcbam?6W@38^>`P*jS2~1MsnMM7(9^4WTUBzlxzFBv~uGhh()D#c~vjV z52{Blfy?!bJ^gi*=k8(Rr8X`UzmC;K*9SCUM#uhhB;gVR&t&1{|J3k{qo1Q#Va z;UpryZ0xA=JeM8295Mc;w zwT2DmyS02j^&hZ#Zbc~l`Cvkj^Ac$)*RpT&{E7<2v3^IO*ZwGdGl=Ik?`dcS{@bJ7 zBKj1aVFx_h1}@r#IEDIn%rjo#Sn3v>tQJ?ABx4scw3h8-ZaQKFPt}~JX}qP zW5#IKeyD)`ECOqIsldQ2(lL*&8^_76{5QbqraEz`JOy2(5FEBap9XAI&>sUq$t8My z+V}j8{eSZ(Y@+*ke&rwetNIUrAiwaJ$*Kc0ww34UvVJ#A$3l>9y?;Nn)g_00h-Iaw zi4@ZE70#Y8)YU3fG+8#KvdH0Ti0CaFW58m^oI4=sWv*^$<_Sr;ZYmM`s}4EbA881R z)IdqAq20LsYZ+(3xwsn((?FIDT|q>NfHfbZz}6(QSzw(`{pdol(SD41zu>2NBo@z9 zBDNvnNOfwhXNc?ht5YID0iw?}#JlCDtc8w)s8$?ZeK6l)OWhNgkayAvG^V_J9Vb=W zY8_PYbp=x>t@_SEcCl}(&f0&sKDwc}xyqMp!n79{SK;tV639-s=iHIaGli1Y=){Ym zA4mw-_~j%;K|TP19b}x=u4P^Rpf*sNa3t8<}|W6@@zwi}mur-uIa+ zXfH(zmYughRJB+f$HwOCIzz)o_Z+J~Z@aAQ^?fqB>fhr_&;-@*MQRv&PwyE6w+{H= z$xWGH9C$a+7}Hd0JcJy@Bg6p>Ht{`dYf*4J>4zS5AWK2DBnB;Gj@S=$;827t;!+lj zv6(yILWVnFLkVfCdN;Ep;v}WuRNtu}AYz?&Q&jt?NP;#PzRxCS+0RD&9g=i@H-5me z4wCL{lJQo2r<6j{e3JNQ;78G-R8w;znTr<}5+8ZEPU${cljKQI{p;43$XAqo}sV)QKu=UQ{8)q(9*+4P+I%&Ouxs5A8$ zY})7eM@9?E0ec^p58dTDEXkxq5Ltu(D%BUvn~7PD2Pv)hr%Zp4Qs8f0@#*UHuTm;z zVXgbPZJ!$bpBX*EIzmFv+j}C(yQQ)8G?B4P^tuRXr53}vbt+Sn>P+6TJ&chVHkV?+ z5GgF4I?nZ=-U;MsmH5-6oIM`lQd(u_1XAmh3*Z2Hv!fUvs}LLwpz^ zL>xj3XMBeOQ;-4U>7dk@*prO@ne(o0(}$y>^*TgO0X0~eFTHIlq$O- zaH?5Iml5_0yXo5HCX%w9t@%DjEWOUfHic&U@WZ#@BwBeai|4rI*ljhaQ6hqjl6^g}-p_3PEVyV6ymxuMwH)RYT`AYbZb!Sa1Xp5ebu0jd zZ-r=50#kwU$rZV{3UJ>$*2-u!FUwwc{3x@SQ3U7(`U+;QP-7VP>R=NN5o4J=_ZJ9O z1GRH>(MDwTtre(NdsY(|df>)VV(q`kPWHJ%cm&Kegu74@RU#*Xybe8udgXydzfO{U zgL@X|e#;`&f8mZ2e;d8{Q%?c@BZM_d0#?fyXzg8%W?#s9Dun(wt(ldP=J_8AQ;-k= zLOG3_5_eoHo&$q_xT5_I$|TfD>}#ZN?#16P2KVf@)3}AFvq-Edk+?sRV{yX>>YDBF zBFtuo(4#1MbUWt2C{RPUA7)%x%xN;FD;j@siaDe}4+&;p!g~2KsV!t+Q;nRFoKf&{ z2vgQ_i`fUhn(clf@tl2sCj2#%Q8}7H2P-qbxll`h;=uzQWC`oinu{=p zVJn9Gf_!G_3uzceO2AogB`nO?yy#YIafPekIwC&fJJUCIwHKBv%rnO?(NrC+pjq-J z5;});=E%Pfw%VB>R|qWUv%`1QV!?zGdXvJiUW719_~5C46gs2FV9G1J?xB`5>Ahpi zrJ6Yo!plS~UKbPy-91SEA zDN5!_^c+6ZCjT=a%Ge5w0>-e+IAb(=MvoIMZNG+b>l=*+abSktj-J%#dLzde4d31b z^1&d|K-6kGBNjsxnxgtln;aO-J`nhQVUO~=EOlVN(~|K^;Us}@c(Yzq17lXf%PGuo zzIy^$mQvVUY21=EcJr`}Z`lRu2T4dKlp3Go(!O8q7O4m$;iLcRlToPsd7Xu53iJqIIggV}CihP)XGz`d8J`hn6vYHhIjLo-08HeUJc>`psrLJe zHR;;>1R(Uby*Avd<(e$@JEmF#m@cwr&lUk6pa|53&vK?L&*&DE+W=K)H9t6!WtFsa zDQ~eebYcZz6#&$}!_|4ORA-}b^_LIEOp}in>aAJ;a9IATdwnZ9cxS|x-=hD6n})^>PCJ|&v;Si7FhhXUF#p+v9ejg0!bijM3H{2&?SnJ$|bQWg7 zoP3U#GFq@~u43@oLHUkzP_}ZqP{j#@&?`mnSWgijWE92Q#QWc6^ndF@_k}bDeG^?P zD?BZI?f{b#49_pHcZ8suaM^@?TwlH-jMb4AztM3{#Ff z4NtK-CbShvxWAgBiq@>TtTzQShc(?+qKf8?E6B|M^vxY-=L#_{z!q#X7~DJ3lD?iA zMSSie9D??Rj*pkIYIzhJ(|h|sxL~c4?E3dZg zru_J+%oa&*6V$2$t9v}-bsc;z=$cdy#EB}>vRiR=y%-KTEFSsRr1=?4)2BExY)j;X zy*|8M$NUKkX7xc;n8A69pcYB8ebj`8cHE1AR>?A(&)MDtN8+;0h7PoIdm#Nnw|sCa zRU`+)nOut}hWM>h@pdX>-ky%852(G)y{Am>Q}a}62v&vI76ve5Kaz8ajU z&Fr$L&Q{}w(oE%ndVk9CgDoeLd^aS*s1uqN0x^3Z>P5mo#QFN_HIt=O8ThJ*DlnN((|$ox5vb4GV#=YML+H5N;vb=M)Qpo)L(0Gnobl65EFO4{3g8in zRdOWV2K@Vx8G&p#f+&Q6D|9<*eg4flC<7k~% zoA5jDX=L6&zHsD*BQ=P;)k<%vGvWkuI3re>;lO@uc`gz&%rrpneG?To1=9Bz9h1!f zHqEq`xdh-|ij(AMfVk5_PfS{F3s+I*_}U9GwA$2${fZ0CaA&(AVDOZrzB=B-cyu_+ z9lA$nyCePv`r*h6z2|06yf1@l-%lv~bKf27e=-M02U80MSv@mDeFytT$2?V0OBPM= zzWg!Dfbpu5(j&u5h$d-@BD9n=2ecZ|yNjK_ccKD+!F$(YDV1#N#R0>`>a&BF*v7{B z!K0SuvpegYsJf)k> z2jL1;frD_iWJg=3AXKa<9R?1+2dXKLb|zb}9OwuTBXePDnJuFH|$jZkeelXEVuG;#DL9EHz z;Y&=6j%X!2SvA+ReMXIX%?cXR@5q~xiS?!E^4!f8&1IT-YfE>v}38uL+tuvqC)FHW)|!2vj==FBbPBCFGz1&tmC zJy3{|Nf#)xZwz1RUUz$7YxEnTx8&Gk*;2Icz3GUvm0h^%;cx5odnPEmCZ|8U+=8FN{Q@6X#R(S-U@9Q2W zJ$_yPcTX_?hW*oPv42f-`@@V^JA&U$Ui?fd3YQ2*Xp_-;{H4GlP`rHgZ})=;aC2GVg4EP>31uS zv45U1f9Nd#wM_5Jxqtt_zj-zB82aZq=!YTozt&5{e}n$b$ogY5KhJ^vx;wW>|7_;z z5$ng;KTl6RB$7=aJqjt@l=`cv4x-OArD2Xzg8dpzgzfw3F|Tb&$snoSqNnOcl;-6ERPNRe3ATh zizJ!<-M~{NfX5bo&f9Q& literal 0 HcmV?d00001 diff --git a/lucene/core/src/generated/jdk/panama-foreign-jdk19.apijar b/lucene/core/src/generated/jdk/panama-foreign-jdk19.apijar deleted file mode 100644 index c9b73d9193bfd419dfced6723bf41d624d226478..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20781 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 diff --git a/lucene/core/src/generated/jdk/panama-foreign-jdk20.apijar b/lucene/core/src/generated/jdk/panama-foreign-jdk20.apijar deleted file mode 100644 index 03baf38a193814644351b6a2145e87ed70987b7c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19487 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≠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 diff --git a/lucene/core/src/java/org/apache/lucene/analysis/WordlistLoader.java b/lucene/core/src/java/org/apache/lucene/analysis/WordlistLoader.java index 30ada92eb39b..8e18f4ad76d3 100644 --- a/lucene/core/src/java/org/apache/lucene/analysis/WordlistLoader.java +++ b/lucene/core/src/java/org/apache/lucene/analysis/WordlistLoader.java @@ -40,9 +40,9 @@ public class WordlistLoader { private WordlistLoader() {} /** - * Reads lines from a Reader and adds every line as an entry to a CharArraySet (omitting leading - * and trailing whitespace). Every line of the Reader should contain only one word. The words need - * to be in lowercase if you make use of an Analyzer which uses LowerCaseFilter (like + * Reads lines from a Reader and adds every non-blank line as an entry to a CharArraySet (omitting + * leading and trailing whitespace). Every line of the Reader should contain only one word. The + * words need to be in lowercase if you make use of an Analyzer which uses LowerCaseFilter (like * StandardAnalyzer). * * @param reader Reader containing the wordlist @@ -53,7 +53,10 @@ public static CharArraySet getWordSet(Reader reader, CharArraySet result) throws try (BufferedReader br = getBufferedReader(reader)) { String word = null; while ((word = br.readLine()) != null) { - result.add(word.trim()); + word = word.trim(); + // skip blank lines + if (word.isEmpty()) continue; + result.add(word); } } return result; @@ -101,10 +104,10 @@ public static CharArraySet getWordSet(InputStream stream, Charset charset) throw } /** - * Reads lines from a Reader and adds every non-comment line as an entry to a CharArraySet - * (omitting leading and trailing whitespace). Every line of the Reader should contain only one - * word. The words need to be in lowercase if you make use of an Analyzer which uses - * LowerCaseFilter (like StandardAnalyzer). + * Reads lines from a Reader and adds every non-blank non-comment line as an entry to a + * CharArraySet (omitting leading and trailing whitespace). Every line of the Reader should + * contain only one word. The words need to be in lowercase if you make use of an Analyzer which + * uses LowerCaseFilter (like StandardAnalyzer). * * @param reader Reader containing the wordlist * @param comment The string representing a comment. @@ -117,7 +120,10 @@ public static CharArraySet getWordSet(Reader reader, String comment, CharArraySe String word = null; while ((word = br.readLine()) != null) { if (word.startsWith(comment) == false) { - result.add(word.trim()); + word = word.trim(); + // skip blank lines + if (word.isEmpty()) continue; + result.add(word); } } } diff --git a/lucene/core/src/java/org/apache/lucene/codecs/lucene90/IndexedDISI.java b/lucene/core/src/java/org/apache/lucene/codecs/lucene90/IndexedDISI.java index 8da289e3ad35..512ab4b1e556 100644 --- a/lucene/core/src/java/org/apache/lucene/codecs/lucene90/IndexedDISI.java +++ b/lucene/core/src/java/org/apache/lucene/codecs/lucene90/IndexedDISI.java @@ -110,12 +110,12 @@ public final class IndexedDISI extends DocIdSetIterator { private static void flush( int block, FixedBitSet buffer, int cardinality, byte denseRankPower, IndexOutput out) throws IOException { - assert block >= 0 && block < 65536; + assert block >= 0 && block < BLOCK_SIZE; out.writeShort((short) block); - assert cardinality > 0 && cardinality <= 65536; + assert cardinality > 0 && cardinality <= BLOCK_SIZE; out.writeShort((short) (cardinality - 1)); if (cardinality > MAX_ARRAY_LENGTH) { - if (cardinality != 65536) { // all docs are set + if (cardinality != BLOCK_SIZE) { // all docs are set if (denseRankPower != -1) { final byte[] rank = createRank(buffer, denseRankPower); out.writeBytes(rank, rank.length); @@ -220,7 +220,7 @@ public static short writeBitSet(DocIdSetIterator it, IndexOutput out, byte dense // Flush block flush(prevBlock, buffer, blockCardinality, denseRankPower, out); // Reset for next block - buffer.clear(0, buffer.length()); + buffer.clear(); totalCardinality += blockCardinality; blockCardinality = 0; } @@ -234,7 +234,7 @@ public static short writeBitSet(DocIdSetIterator it, IndexOutput out, byte dense jumps, out.getFilePointer() - origo, totalCardinality, jumpBlockIndex, prevBlock + 1); totalCardinality += blockCardinality; flush(prevBlock, buffer, blockCardinality, denseRankPower, out); - buffer.clear(0, buffer.length()); + buffer.clear(); prevBlock++; } final int lastBlock = @@ -418,6 +418,7 @@ public static RandomAccessInput createJumpTable( // SPARSE variables boolean exists; + int nextExistDocInBlock = -1; // DENSE variables long word; @@ -495,7 +496,8 @@ private void readBlockHeader() throws IOException { if (numValues <= MAX_ARRAY_LENGTH) { method = Method.SPARSE; blockEnd = slice.getFilePointer() + (numValues << 1); - } else if (numValues == 65536) { + nextExistDocInBlock = -1; + } else if (numValues == BLOCK_SIZE) { method = Method.ALL; blockEnd = slice.getFilePointer(); gap = block - index - 1; @@ -550,6 +552,7 @@ boolean advanceWithinBlock(IndexedDISI disi, int target) throws IOException { if (doc >= targetInBlock) { disi.doc = disi.block | doc; disi.exists = true; + disi.nextExistDocInBlock = doc; return true; } } @@ -560,6 +563,10 @@ boolean advanceWithinBlock(IndexedDISI disi, int target) throws IOException { boolean advanceExactWithinBlock(IndexedDISI disi, int target) throws IOException { final int targetInBlock = target & 0xFFFF; // TODO: binary search + if (disi.nextExistDocInBlock > targetInBlock) { + assert !disi.exists; + return false; + } if (target == disi.doc) { return disi.exists; } @@ -567,6 +574,7 @@ boolean advanceExactWithinBlock(IndexedDISI disi, int target) throws IOException int doc = Short.toUnsignedInt(disi.slice.readShort()); disi.index++; if (doc >= targetInBlock) { + disi.nextExistDocInBlock = doc; if (doc != targetInBlock) { disi.index--; disi.slice.seek(disi.slice.getFilePointer() - Short.BYTES); diff --git a/lucene/core/src/java/org/apache/lucene/document/BinaryRangeFieldRangeQuery.java b/lucene/core/src/java/org/apache/lucene/document/BinaryRangeFieldRangeQuery.java index ec814a4b0a7e..b225f4d98fe2 100644 --- a/lucene/core/src/java/org/apache/lucene/document/BinaryRangeFieldRangeQuery.java +++ b/lucene/core/src/java/org/apache/lucene/document/BinaryRangeFieldRangeQuery.java @@ -21,7 +21,6 @@ import java.util.Arrays; import java.util.Objects; import org.apache.lucene.index.DocValues; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.search.ConstantScoreScorer; @@ -90,8 +89,8 @@ public void visit(QueryVisitor visitor) { } @Override - public Query rewrite(IndexReader reader) throws IOException { - return super.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + return super.rewrite(indexSearcher); } private BinaryRangeDocValues getValues(LeafReader reader, String field) throws IOException { diff --git a/lucene/core/src/java/org/apache/lucene/document/DoubleRangeSlowRangeQuery.java b/lucene/core/src/java/org/apache/lucene/document/DoubleRangeSlowRangeQuery.java index 6406b1be81a2..f0f9040d08c9 100644 --- a/lucene/core/src/java/org/apache/lucene/document/DoubleRangeSlowRangeQuery.java +++ b/lucene/core/src/java/org/apache/lucene/document/DoubleRangeSlowRangeQuery.java @@ -20,7 +20,7 @@ import java.io.IOException; import java.util.Arrays; import java.util.Objects; -import org.apache.lucene.index.IndexReader; +import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.QueryVisitor; @@ -79,8 +79,8 @@ public String toString(String field) { } @Override - public Query rewrite(IndexReader reader) throws IOException { - return super.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + return super.rewrite(indexSearcher); } private static byte[] encodeRanges(double[] min, double[] max) { diff --git a/lucene/core/src/java/org/apache/lucene/document/FeatureField.java b/lucene/core/src/java/org/apache/lucene/document/FeatureField.java index 27e689644594..85c3bad35199 100644 --- a/lucene/core/src/java/org/apache/lucene/document/FeatureField.java +++ b/lucene/core/src/java/org/apache/lucene/document/FeatureField.java @@ -31,6 +31,7 @@ import org.apache.lucene.search.DoubleValuesSource; import org.apache.lucene.search.Explanation; import org.apache.lucene.search.FieldDoc; +import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.SortField; import org.apache.lucene.search.similarities.BM25Similarity; @@ -223,7 +224,7 @@ abstract static class FeatureFunction { abstract Explanation explain(String field, String feature, float w, int freq); - FeatureFunction rewrite(IndexReader reader) throws IOException { + FeatureFunction rewrite(IndexSearcher indexSearcher) throws IOException { return this; } } @@ -340,11 +341,11 @@ static final class SaturationFunction extends FeatureFunction { } @Override - public FeatureFunction rewrite(IndexReader reader) throws IOException { + public FeatureFunction rewrite(IndexSearcher indexSearcher) throws IOException { if (pivot != null) { - return super.rewrite(reader); + return super.rewrite(indexSearcher); } - float newPivot = computePivotFeatureValue(reader, field, feature); + float newPivot = computePivotFeatureValue(indexSearcher.getIndexReader(), field, feature); return new SaturationFunction(field, feature, newPivot); } diff --git a/lucene/core/src/java/org/apache/lucene/document/FeatureQuery.java b/lucene/core/src/java/org/apache/lucene/document/FeatureQuery.java index de899a96d4ea..8b1ea8c47258 100644 --- a/lucene/core/src/java/org/apache/lucene/document/FeatureQuery.java +++ b/lucene/core/src/java/org/apache/lucene/document/FeatureQuery.java @@ -20,7 +20,6 @@ import java.util.Objects; import org.apache.lucene.document.FeatureField.FeatureFunction; import org.apache.lucene.index.ImpactsEnum; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.PostingsEnum; import org.apache.lucene.index.Term; @@ -52,12 +51,12 @@ final class FeatureQuery extends Query { } @Override - public Query rewrite(IndexReader reader) throws IOException { - FeatureFunction rewritten = function.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + FeatureFunction rewritten = function.rewrite(indexSearcher); if (function != rewritten) { return new FeatureQuery(fieldName, featureName, rewritten); } - return super.rewrite(reader); + return super.rewrite(indexSearcher); } @Override diff --git a/lucene/core/src/java/org/apache/lucene/document/FloatRangeSlowRangeQuery.java b/lucene/core/src/java/org/apache/lucene/document/FloatRangeSlowRangeQuery.java index 9c011621e066..62981f4870aa 100644 --- a/lucene/core/src/java/org/apache/lucene/document/FloatRangeSlowRangeQuery.java +++ b/lucene/core/src/java/org/apache/lucene/document/FloatRangeSlowRangeQuery.java @@ -20,7 +20,7 @@ import java.io.IOException; import java.util.Arrays; import java.util.Objects; -import org.apache.lucene.index.IndexReader; +import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.QueryVisitor; @@ -79,8 +79,8 @@ public String toString(String field) { } @Override - public Query rewrite(IndexReader reader) throws IOException { - return super.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + return super.rewrite(indexSearcher); } private static byte[] encodeRanges(float[] min, float[] max) { diff --git a/lucene/core/src/java/org/apache/lucene/document/IntRangeSlowRangeQuery.java b/lucene/core/src/java/org/apache/lucene/document/IntRangeSlowRangeQuery.java index cd0714a52909..99d5fa212f67 100644 --- a/lucene/core/src/java/org/apache/lucene/document/IntRangeSlowRangeQuery.java +++ b/lucene/core/src/java/org/apache/lucene/document/IntRangeSlowRangeQuery.java @@ -19,7 +19,7 @@ import java.io.IOException; import java.util.Arrays; import java.util.Objects; -import org.apache.lucene.index.IndexReader; +import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.QueryVisitor; @@ -77,8 +77,8 @@ public String toString(String field) { } @Override - public Query rewrite(IndexReader reader) throws IOException { - return super.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + return super.rewrite(indexSearcher); } private static byte[] encodeRanges(int[] min, int[] max) { diff --git a/lucene/core/src/java/org/apache/lucene/document/KnnByteVectorField.java b/lucene/core/src/java/org/apache/lucene/document/KnnByteVectorField.java index fabbc5259e3b..87cb6a9f056e 100644 --- a/lucene/core/src/java/org/apache/lucene/document/KnnByteVectorField.java +++ b/lucene/core/src/java/org/apache/lucene/document/KnnByteVectorField.java @@ -17,6 +17,7 @@ package org.apache.lucene.document; +import java.util.Objects; import org.apache.lucene.index.ByteVectorValues; import org.apache.lucene.index.VectorEncoding; import org.apache.lucene.index.VectorSimilarityFunction; @@ -100,7 +101,7 @@ public static FieldType createFieldType( public KnnByteVectorField( String name, byte[] vector, VectorSimilarityFunction similarityFunction) { super(name, createType(vector, similarityFunction)); - fieldsData = vector; + fieldsData = vector; // null-check done above } /** @@ -136,6 +137,11 @@ public KnnByteVectorField(String name, byte[] vector, FieldType fieldType) { + " using byte[] but the field encoding is " + fieldType.vectorEncoding()); } + Objects.requireNonNull(vector, "vector value must not be null"); + if (vector.length != fieldType.vectorDimension()) { + throw new IllegalArgumentException( + "The number of vector dimensions does not match the field type"); + } fieldsData = vector; } diff --git a/lucene/core/src/java/org/apache/lucene/document/KnnFloatVectorField.java b/lucene/core/src/java/org/apache/lucene/document/KnnFloatVectorField.java index d6673293c720..9d1cd02c013e 100644 --- a/lucene/core/src/java/org/apache/lucene/document/KnnFloatVectorField.java +++ b/lucene/core/src/java/org/apache/lucene/document/KnnFloatVectorField.java @@ -17,6 +17,7 @@ package org.apache.lucene.document; +import java.util.Objects; import org.apache.lucene.index.FloatVectorValues; import org.apache.lucene.index.VectorEncoding; import org.apache.lucene.index.VectorSimilarityFunction; @@ -101,7 +102,7 @@ public static Query newVectorQuery(String field, float[] queryVector, int k) { public KnnFloatVectorField( String name, float[] vector, VectorSimilarityFunction similarityFunction) { super(name, createType(vector, similarityFunction)); - fieldsData = vector; + fieldsData = VectorUtil.checkFinite(vector); // null check done above } /** @@ -137,7 +138,12 @@ public KnnFloatVectorField(String name, float[] vector, FieldType fieldType) { + " using float[] but the field encoding is " + fieldType.vectorEncoding()); } - fieldsData = vector; + Objects.requireNonNull(vector, "vector value must not be null"); + if (vector.length != fieldType.vectorDimension()) { + throw new IllegalArgumentException( + "The number of vector dimensions does not match the field type"); + } + fieldsData = VectorUtil.checkFinite(vector); } /** Return the vector value of this field */ diff --git a/lucene/core/src/java/org/apache/lucene/document/LongRangeSlowRangeQuery.java b/lucene/core/src/java/org/apache/lucene/document/LongRangeSlowRangeQuery.java index a4c164524fc5..b86d64bef62c 100644 --- a/lucene/core/src/java/org/apache/lucene/document/LongRangeSlowRangeQuery.java +++ b/lucene/core/src/java/org/apache/lucene/document/LongRangeSlowRangeQuery.java @@ -20,7 +20,7 @@ import java.io.IOException; import java.util.Arrays; import java.util.Objects; -import org.apache.lucene.index.IndexReader; +import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.QueryVisitor; @@ -79,8 +79,8 @@ public String toString(String field) { } @Override - public Query rewrite(IndexReader reader) throws IOException { - return super.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + return super.rewrite(indexSearcher); } private static byte[] encodeRanges(long[] min, long[] max) { diff --git a/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesRangeQuery.java b/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesRangeQuery.java index fb23056126bb..21264409136f 100644 --- a/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesRangeQuery.java +++ b/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesRangeQuery.java @@ -19,7 +19,6 @@ import java.io.IOException; import java.util.Objects; import org.apache.lucene.index.DocValues; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.NumericDocValues; import org.apache.lucene.index.SortedNumericDocValues; @@ -84,11 +83,11 @@ public String toString(String field) { } @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { if (lowerValue == Long.MIN_VALUE && upperValue == Long.MAX_VALUE) { return new FieldExistsQuery(field); } - return super.rewrite(reader); + return super.rewrite(indexSearcher); } @Override diff --git a/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesSetQuery.java b/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesSetQuery.java index 72d5d42b30a3..fe5e8c3afedd 100644 --- a/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesSetQuery.java +++ b/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesSetQuery.java @@ -20,7 +20,6 @@ import java.util.Arrays; import java.util.Objects; import org.apache.lucene.index.DocValues; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.NumericDocValues; import org.apache.lucene.index.SortedNumericDocValues; @@ -85,11 +84,11 @@ public long ramBytesUsed() { } @Override - public Query rewrite(IndexReader indexReader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { if (numbers.size() == 0) { return new MatchNoDocsQuery(); } - return super.rewrite(indexReader); + return super.rewrite(indexSearcher); } @Override diff --git a/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesRangeQuery.java b/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesRangeQuery.java index f7eab990d3d5..928257cbd1fa 100644 --- a/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesRangeQuery.java +++ b/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesRangeQuery.java @@ -19,7 +19,6 @@ import java.io.IOException; import java.util.Objects; import org.apache.lucene.index.DocValues; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.SortedDocValues; import org.apache.lucene.index.SortedSetDocValues; @@ -98,11 +97,11 @@ public String toString(String field) { } @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { if (lowerValue == null && upperValue == null) { return new FieldExistsQuery(field); } - return super.rewrite(reader); + return super.rewrite(indexSearcher); } @Override diff --git a/lucene/core/src/java/org/apache/lucene/geo/Tessellator.java b/lucene/core/src/java/org/apache/lucene/geo/Tessellator.java index 5179037fa54f..ae0190f9d459 100644 --- a/lucene/core/src/java/org/apache/lucene/geo/Tessellator.java +++ b/lucene/core/src/java/org/apache/lucene/geo/Tessellator.java @@ -1090,17 +1090,22 @@ private static final Node splitPolygon(final Node a, final Node b, boolean edgeF * Determines whether a diagonal between two polygon nodes lies within a polygon interior. (This * determines the validity of the ray.) * */ - private static final boolean isValidDiagonal(final Node a, final Node b) { + private static boolean isValidDiagonal(final Node a, final Node b) { + if (a.next.idx == b.idx + || a.previous.idx == b.idx + // check next edges are locally visible + || isLocallyInside(a.previous, b) == false + || isLocallyInside(b.next, a) == false + // check polygons are CCW in both sides + || isCWPolygon(a, b) == false + || isCWPolygon(b, a) == false) { + return false; + } if (isVertexEquals(a, b)) { - // If points are equal then use it if they are valid polygons - return isCWPolygon(a, b); + return true; } - return a.next.idx != b.idx - && a.previous.idx != b.idx - && isLocallyInside(a, b) + return isLocallyInside(a, b) && isLocallyInside(b, a) - && isLocallyInside(a.previous, b) - && isLocallyInside(b.next, a) && middleInsert(a, a.getX(), a.getY(), b.getX(), b.getY()) // make sure we don't introduce collinear lines && area(a.previous.getX(), a.previous.getY(), a.getX(), a.getY(), b.getX(), b.getY()) != 0 @@ -1114,7 +1119,7 @@ && area(a.getX(), a.getY(), b.getX(), b.getY(), b.previous.getX(), b.previous.ge /** Determine whether the polygon defined between node start and node end is CW */ private static boolean isCWPolygon(final Node start, final Node end) { // The polygon must be CW - return (signedArea(start, end) < 0) ? true : false; + return signedArea(start, end) < 0; } /** Determine the signed area between node start and node end */ diff --git a/lucene/core/src/java/org/apache/lucene/index/CachingMergeContext.java b/lucene/core/src/java/org/apache/lucene/index/CachingMergeContext.java new file mode 100644 index 000000000000..a9974c64e0b1 --- /dev/null +++ b/lucene/core/src/java/org/apache/lucene/index/CachingMergeContext.java @@ -0,0 +1,61 @@ +/* + * 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.index; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Set; +import org.apache.lucene.util.InfoStream; + +/** + * a wrapper of IndexWriter MergeContext. Try to cache the {@link + * #numDeletesToMerge(SegmentCommitInfo)} result in merge phase, to avoid duplicate calculation + */ +class CachingMergeContext implements MergePolicy.MergeContext { + final MergePolicy.MergeContext mergeContext; + final HashMap cachedNumDeletesToMerge = new HashMap<>(); + + CachingMergeContext(MergePolicy.MergeContext mergeContext) { + this.mergeContext = mergeContext; + } + + @Override + public final int numDeletesToMerge(SegmentCommitInfo info) throws IOException { + Integer numDeletesToMerge = cachedNumDeletesToMerge.get(info); + if (numDeletesToMerge != null) { + return numDeletesToMerge; + } + numDeletesToMerge = mergeContext.numDeletesToMerge(info); + cachedNumDeletesToMerge.put(info, numDeletesToMerge); + return numDeletesToMerge; + } + + @Override + public final int numDeletedDocs(SegmentCommitInfo info) { + return mergeContext.numDeletedDocs(info); + } + + @Override + public final InfoStream getInfoStream() { + return mergeContext.getInfoStream(); + } + + @Override + public final Set getMergingSegments() { + return mergeContext.getMergingSegments(); + } +} diff --git a/lucene/core/src/java/org/apache/lucene/index/DocumentsWriterDeleteQueue.java b/lucene/core/src/java/org/apache/lucene/index/DocumentsWriterDeleteQueue.java index ed86416a2b19..4d8bfd054654 100644 --- a/lucene/core/src/java/org/apache/lucene/index/DocumentsWriterDeleteQueue.java +++ b/lucene/core/src/java/org/apache/lucene/index/DocumentsWriterDeleteQueue.java @@ -142,6 +142,10 @@ static Node newNode(Term term) { return new TermNode(term); } + static Node newNode(Query query) { + return new QueryNode(query); + } + static Node newNode(DocValuesUpdate... updates) { return new DocValuesUpdatesNode(updates); } @@ -437,6 +441,23 @@ public String toString() { } } + private static final class QueryNode extends Node { + + QueryNode(Query query) { + super(query); + } + + @Override + void apply(BufferedUpdates bufferedDeletes, int docIDUpto) { + bufferedDeletes.addQuery(item, docIDUpto); + } + + @Override + public String toString() { + return "del=" + item; + } + } + private static final class QueryArrayNode extends Node { QueryArrayNode(Query[] query) { super(query); diff --git a/lucene/core/src/java/org/apache/lucene/index/ExitableDirectoryReader.java b/lucene/core/src/java/org/apache/lucene/index/ExitableDirectoryReader.java index b180d3bdda3d..a572b2258af5 100644 --- a/lucene/core/src/java/org/apache/lucene/index/ExitableDirectoryReader.java +++ b/lucene/core/src/java/org/apache/lucene/index/ExitableDirectoryReader.java @@ -36,7 +36,7 @@ */ public class ExitableDirectoryReader extends FilterDirectoryReader { - private QueryTimeout queryTimeout; + private final QueryTimeout queryTimeout; /** Exception that is thrown to prematurely terminate a term enumeration. */ @SuppressWarnings("serial") @@ -50,7 +50,7 @@ public ExitingReaderException(String msg) { /** Wrapper class for a SubReaderWrapper that is used by the ExitableDirectoryReader. */ public static class ExitableSubReaderWrapper extends SubReaderWrapper { - private QueryTimeout queryTimeout; + private final QueryTimeout queryTimeout; /** Constructor * */ public ExitableSubReaderWrapper(QueryTimeout queryTimeout) { @@ -810,7 +810,7 @@ public static class ExitableTermsEnum extends FilterTermsEnum { // Create bit mask in the form of 0000 1111 for efficient checking private static final int NUM_CALLS_PER_TIMEOUT_CHECK = (1 << 4) - 1; // 15 private int calls; - private QueryTimeout queryTimeout; + private final QueryTimeout queryTimeout; /** Constructor * */ public ExitableTermsEnum(TermsEnum termsEnum, QueryTimeout queryTimeout) { diff --git a/lucene/core/src/java/org/apache/lucene/index/FieldInfo.java b/lucene/core/src/java/org/apache/lucene/index/FieldInfo.java index c48b851ae526..df2054c18846 100644 --- a/lucene/core/src/java/org/apache/lucene/index/FieldInfo.java +++ b/lucene/core/src/java/org/apache/lucene/index/FieldInfo.java @@ -400,6 +400,150 @@ static void verifySameVectorOptions( } } + /* + This method will create a new instance of FieldInfo if any attribute changes (and it changes in a compatible way). + It is intended only to be used in indices where schema validation is not strict (legacy indices). It will return null + if no changes are done on this FieldInfo + */ + FieldInfo handleLegacySupportedUpdates(FieldInfo otherFi) { + IndexOptions newIndexOptions = this.indexOptions; + boolean newStoreTermVector = this.storeTermVector; + boolean newOmitNorms = this.omitNorms; + boolean newStorePayloads = this.storePayloads; + DocValuesType newDocValues = this.docValuesType; + int newPointDimensionCount = this.pointDimensionCount; + int newPointNumBytes = this.pointNumBytes; + int newPointIndexDimensionCount = this.pointIndexDimensionCount; + long newDvGen = this.dvGen; + + boolean fieldInfoChanges = false; + // System.out.println("FI.update field=" + name + " indexed=" + indexed + " omitNorms=" + + // omitNorms + " this.omitNorms=" + this.omitNorms); + if (this.indexOptions != otherFi.indexOptions) { + if (this.indexOptions == IndexOptions.NONE) { + newIndexOptions = otherFi.indexOptions; + fieldInfoChanges = true; + } else if (otherFi.indexOptions != IndexOptions.NONE) { + throw new IllegalArgumentException( + "cannot change field \"" + + name + + "\" from index options=" + + this.indexOptions + + " to inconsistent index options=" + + otherFi.indexOptions); + } + } + + if (this.pointDimensionCount != otherFi.pointDimensionCount + && otherFi.pointDimensionCount != 0) { + if (this.pointDimensionCount == 0) { + fieldInfoChanges = true; + newPointDimensionCount = otherFi.pointDimensionCount; + } else { + throw new IllegalArgumentException( + "cannot change field \"" + + name + + "\" from points dimensionCount=" + + this.pointDimensionCount + + " to inconsistent dimensionCount=" + + otherFi.pointDimensionCount); + } + } + + if (this.pointIndexDimensionCount != otherFi.pointIndexDimensionCount + && otherFi.pointIndexDimensionCount != 0) { + if (this.pointIndexDimensionCount == 0) { + fieldInfoChanges = true; + newPointIndexDimensionCount = otherFi.pointIndexDimensionCount; + } else { + throw new IllegalArgumentException( + "cannot change field \"" + + name + + "\" from points indexDimensionCount=" + + this.pointIndexDimensionCount + + " to inconsistent indexDimensionCount=" + + otherFi.pointIndexDimensionCount); + } + } + + if (this.pointNumBytes != otherFi.pointNumBytes && otherFi.pointNumBytes != 0) { + if (this.pointNumBytes == 0) { + fieldInfoChanges = true; + newPointNumBytes = otherFi.pointNumBytes; + } else { + throw new IllegalArgumentException( + "cannot change field \"" + + name + + "\" from points numBytes=" + + this.pointNumBytes + + " to inconsistent numBytes=" + + otherFi.pointNumBytes); + } + } + + if (newIndexOptions + != IndexOptions.NONE) { // if updated field data is not for indexing, leave the updates out + if (this.storeTermVector != otherFi.storeTermVector && this.storeTermVector == false) { + fieldInfoChanges = true; + newStoreTermVector = true; // once vector, always vector + } + if (this.storePayloads != otherFi.storePayloads + && this.storePayloads == false + && newIndexOptions.compareTo(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS) >= 0) { + fieldInfoChanges = true; + newStorePayloads = true; + } + + // Awkward: only drop norms if incoming update is indexed: + if (otherFi.indexOptions != IndexOptions.NONE + && this.omitNorms != otherFi.omitNorms + && this.omitNorms == false) { + fieldInfoChanges = true; + newOmitNorms = true; // if one require omitNorms at least once, it remains off for life + } + } + + if (otherFi.docValuesType != DocValuesType.NONE + && otherFi.docValuesType != this.docValuesType) { + if (this.docValuesType == DocValuesType.NONE) { + fieldInfoChanges = true; + newDocValues = otherFi.docValuesType; + newDvGen = otherFi.dvGen; + } else { + throw new IllegalArgumentException( + "cannot change DocValues type from " + + docValuesType + + " to " + + otherFi.docValuesType + + " for field \"" + + name + + "\""); + } + } + + if (!fieldInfoChanges) { + return null; + } + return new FieldInfo( + this.name, + this.number, + newStoreTermVector, + newOmitNorms, + newStorePayloads, + newIndexOptions, + newDocValues, + newDvGen, + this.attributes, // attributes don't need to be handled here because they are handled for + // the non-legacy case in FieldInfos + newPointDimensionCount, + newPointIndexDimensionCount, + newPointNumBytes, + this.vectorDimension, + this.vectorEncoding, + this.vectorSimilarityFunction, + this.softDeletesField); + } + /** * Record that this field is indexed with points, with the specified number of dimensions and * bytes per dimension. diff --git a/lucene/core/src/java/org/apache/lucene/index/FieldInfos.java b/lucene/core/src/java/org/apache/lucene/index/FieldInfos.java index 7029303992ed..85aac5439d3c 100644 --- a/lucene/core/src/java/org/apache/lucene/index/FieldInfos.java +++ b/lucene/core/src/java/org/apache/lucene/index/FieldInfos.java @@ -628,6 +628,48 @@ FieldInfo constructFieldInfo(String fieldName, DocValuesType dvType, int newFiel isSoftDeletesField); } + synchronized void setDocValuesType(int number, String name, DocValuesType dvType) { + verifyConsistent(number, name, dvType); + docValuesType.put(name, dvType); + } + + synchronized void verifyConsistent(Integer number, String name, DocValuesType dvType) { + if (name.equals(numberToName.get(number)) == false) { + throw new IllegalArgumentException( + "field number " + + number + + " is already mapped to field name \"" + + numberToName.get(number) + + "\", not \"" + + name + + "\""); + } + if (number.equals(nameToNumber.get(name)) == false) { + throw new IllegalArgumentException( + "field name \"" + + name + + "\" is already mapped to field number \"" + + nameToNumber.get(name) + + "\", not \"" + + number + + "\""); + } + DocValuesType currentDVType = docValuesType.get(name); + if (dvType != DocValuesType.NONE + && currentDVType != null + && currentDVType != DocValuesType.NONE + && dvType != currentDVType) { + throw new IllegalArgumentException( + "cannot change DocValues type from " + + currentDVType + + " to " + + dvType + + " for field \"" + + name + + "\""); + } + } + synchronized Set getFieldNames() { return Set.copyOf(nameToNumber.keySet()); } @@ -708,6 +750,26 @@ FieldInfo add(FieldInfo fi, long dvGen) { final FieldInfo curFi = fieldInfo(fi.getName()); if (curFi != null) { curFi.verifySameSchema(fi, globalFieldNumbers.strictlyConsistent); + + if (!globalFieldNumbers.strictlyConsistent) { + // For the not strictly consistent case (legacy index), we may need to merge the + // FieldInfo instances + FieldInfo updatedFieldInfo = curFi.handleLegacySupportedUpdates(fi); + if (updatedFieldInfo != null) { + if (curFi.getDocValuesType() == DocValuesType.NONE + && updatedFieldInfo.getDocValuesType() != DocValuesType.NONE) { + // Must also update docValuesType map so it's + // aware of this field's DocValuesType. This will throw IllegalArgumentException if + // an illegal type change was attempted. + globalFieldNumbers.setDocValuesType( + updatedFieldInfo.number, + updatedFieldInfo.getName(), + updatedFieldInfo.getDocValuesType()); + } + // Since the FieldInfo changed, update in map + byName.put(fi.getName(), updatedFieldInfo); + } + } if (fi.attributes() != null) { fi.attributes().forEach((k, v) -> curFi.putAttribute(k, v)); } diff --git a/lucene/core/src/java/org/apache/lucene/index/IndexWriter.java b/lucene/core/src/java/org/apache/lucene/index/IndexWriter.java index f488e1f83f62..07dca8945548 100644 --- a/lucene/core/src/java/org/apache/lucene/index/IndexWriter.java +++ b/lucene/core/src/java/org/apache/lucene/index/IndexWriter.java @@ -1522,6 +1522,19 @@ public long updateDocuments( delTerm == null ? null : DocumentsWriterDeleteQueue.newNode(delTerm), docs); } + /** + * Similar to {@link #updateDocuments(Term, Iterable)}, but take a query instead of a term to + * identify the documents to be updated + * + * @lucene.experimental + */ + public long updateDocuments( + Query delQuery, Iterable> docs) + throws IOException { + return updateDocuments( + delQuery == null ? null : DocumentsWriterDeleteQueue.newNode(delQuery), docs); + } + private long updateDocuments( final DocumentsWriterDeleteQueue.Node delNode, Iterable> docs) @@ -2202,10 +2215,11 @@ public void forceMergeDeletes(boolean doWait) throws IOException { } final MergePolicy mergePolicy = config.getMergePolicy(); + final CachingMergeContext cachingMergeContext = new CachingMergeContext(this); MergePolicy.MergeSpecification spec; boolean newMergesFound = false; synchronized (this) { - spec = mergePolicy.findForcedDeletesMerges(segmentInfos, this); + spec = mergePolicy.findForcedDeletesMerges(segmentInfos, cachingMergeContext); newMergesFound = spec != null; if (newMergesFound) { final int numMerges = spec.merges.size(); @@ -2315,6 +2329,7 @@ private synchronized MergePolicy.MergeSpecification updatePendingMerges( } final MergePolicy.MergeSpecification spec; + final CachingMergeContext cachingMergeContext = new CachingMergeContext(this); if (maxNumSegments != UNBOUNDED_MAX_MERGE_SEGMENTS) { assert trigger == MergeTrigger.EXPLICIT || trigger == MergeTrigger.MERGE_FINISHED : "Expected EXPLICT or MERGE_FINISHED as trigger even with maxNumSegments set but was: " @@ -2322,7 +2337,10 @@ private synchronized MergePolicy.MergeSpecification updatePendingMerges( spec = mergePolicy.findForcedMerges( - segmentInfos, maxNumSegments, Collections.unmodifiableMap(segmentsToMerge), this); + segmentInfos, + maxNumSegments, + Collections.unmodifiableMap(segmentsToMerge), + cachingMergeContext); if (spec != null) { final int numMerges = spec.merges.size(); for (int i = 0; i < numMerges; i++) { @@ -2334,7 +2352,7 @@ private synchronized MergePolicy.MergeSpecification updatePendingMerges( switch (trigger) { case GET_READER: case COMMIT: - spec = mergePolicy.findFullFlushMerges(trigger, segmentInfos, this); + spec = mergePolicy.findFullFlushMerges(trigger, segmentInfos, cachingMergeContext); break; case ADD_INDEXES: throw new IllegalStateException( @@ -2346,7 +2364,7 @@ private synchronized MergePolicy.MergeSpecification updatePendingMerges( case SEGMENT_FLUSH: case CLOSING: default: - spec = mergePolicy.findMerges(trigger, segmentInfos, this); + spec = mergePolicy.findMerges(trigger, segmentInfos, cachingMergeContext); } } if (spec != null) { diff --git a/lucene/core/src/java/org/apache/lucene/index/QueryTimeout.java b/lucene/core/src/java/org/apache/lucene/index/QueryTimeout.java index 0c64f4c2c9ac..f1e543423670 100644 --- a/lucene/core/src/java/org/apache/lucene/index/QueryTimeout.java +++ b/lucene/core/src/java/org/apache/lucene/index/QueryTimeout.java @@ -17,14 +17,17 @@ package org.apache.lucene.index; /** - * Base for query timeout implementations, which will provide a {@code shouldExit()} method, used - * with {@link ExitableDirectoryReader}. + * Query timeout abstraction that controls whether a query should continue or be stopped. Can be set + * to the searcher through {@link org.apache.lucene.search.IndexSearcher#setTimeout(QueryTimeout)}, + * in which case bulk scoring will be time-bound. Can also be used in combination with {@link + * ExitableDirectoryReader}. */ public interface QueryTimeout { /** - * Called from {@link ExitableDirectoryReader.ExitableTermsEnum#next()} to determine whether to - * stop processing a query. + * Called to determine whether to stop processing a query + * + * @return true if the query should stop, false otherwise */ - public abstract boolean shouldExit(); + boolean shouldExit(); } diff --git a/lucene/core/src/java/org/apache/lucene/index/VectorSimilarityFunction.java b/lucene/core/src/java/org/apache/lucene/index/VectorSimilarityFunction.java index 3646cf65584b..8a515cb79fc9 100644 --- a/lucene/core/src/java/org/apache/lucene/index/VectorSimilarityFunction.java +++ b/lucene/core/src/java/org/apache/lucene/index/VectorSimilarityFunction.java @@ -90,8 +90,8 @@ public float compare(byte[] v1, byte[] v2) { /** * Calculates a similarity score between the two vectors with a specified function. Higher - * similarity scores correspond to closer vectors. The offsets and lengths of the BytesRefs - * determine the vector data that is compared. Each (signed) byte represents a vector dimension. + * similarity scores correspond to closer vectors. Each (signed) byte represents a vector + * dimension. * * @param v1 a vector * @param v2 another vector, of the same dimension diff --git a/lucene/core/src/java/org/apache/lucene/search/AbstractKnnVectorQuery.java b/lucene/core/src/java/org/apache/lucene/search/AbstractKnnVectorQuery.java index eaa7cc1e8337..072846785723 100644 --- a/lucene/core/src/java/org/apache/lucene/search/AbstractKnnVectorQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/AbstractKnnVectorQuery.java @@ -19,9 +19,13 @@ import static org.apache.lucene.search.DocIdSetIterator.NO_MORE_DOCS; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; +import java.util.List; import java.util.Objects; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.FutureTask; import org.apache.lucene.codecs.KnnVectorsReader; import org.apache.lucene.index.FieldInfo; import org.apache.lucene.index.IndexReader; @@ -29,6 +33,7 @@ import org.apache.lucene.util.BitSet; import org.apache.lucene.util.BitSetIterator; import org.apache.lucene.util.Bits; +import org.apache.lucene.util.ThreadInterruptedException; /** * Uses {@link KnnVectorsReader#search} to perform nearest neighbour search. @@ -51,7 +56,7 @@ abstract class AbstractKnnVectorQuery extends Query { private final Query filter; public AbstractKnnVectorQuery(String field, int k, Query filter) { - this.field = field; + this.field = Objects.requireNonNull(field, "field"); this.k = k; if (k < 1) { throw new IllegalArgumentException("k must be at least 1, got: " + k); @@ -60,12 +65,11 @@ public AbstractKnnVectorQuery(String field, int k, Query filter) { } @Override - public Query rewrite(IndexReader reader) throws IOException { - TopDocs[] perLeafResults = new TopDocs[reader.leaves().size()]; + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + IndexReader reader = indexSearcher.getIndexReader(); - Weight filterWeight = null; + final Weight filterWeight; if (filter != null) { - IndexSearcher indexSearcher = new IndexSearcher(reader); BooleanQuery booleanQuery = new BooleanQuery.Builder() .add(filter, BooleanClause.Occur.FILTER) @@ -73,17 +77,17 @@ public Query rewrite(IndexReader reader) throws IOException { .build(); Query rewritten = indexSearcher.rewrite(booleanQuery); filterWeight = indexSearcher.createWeight(rewritten, ScoreMode.COMPLETE_NO_SCORES, 1f); + } else { + filterWeight = null; } - for (LeafReaderContext ctx : reader.leaves()) { - TopDocs results = searchLeaf(ctx, filterWeight); - if (ctx.docBase > 0) { - for (ScoreDoc scoreDoc : results.scoreDocs) { - scoreDoc.doc += ctx.docBase; - } - } - perLeafResults[ctx.ord] = results; - } + SliceExecutor sliceExecutor = indexSearcher.getSliceExecutor(); + // in case of parallel execution, the leaf results are not ordered by leaf context's ordinal + TopDocs[] perLeafResults = + (sliceExecutor == null) + ? sequentialSearch(reader.leaves(), filterWeight) + : parallelSearch(indexSearcher.getSlices(), filterWeight, sliceExecutor); + // Merge sort the results TopDocs topK = TopDocs.merge(k, perLeafResults); if (topK.scoreDocs.length == 0) { @@ -92,7 +96,67 @@ public Query rewrite(IndexReader reader) throws IOException { return createRewrittenQuery(reader, topK); } + private TopDocs[] sequentialSearch( + List leafReaderContexts, Weight filterWeight) { + try { + TopDocs[] perLeafResults = new TopDocs[leafReaderContexts.size()]; + for (LeafReaderContext ctx : leafReaderContexts) { + perLeafResults[ctx.ord] = searchLeaf(ctx, filterWeight); + } + return perLeafResults; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private TopDocs[] parallelSearch( + IndexSearcher.LeafSlice[] slices, Weight filterWeight, SliceExecutor sliceExecutor) { + + List> tasks = new ArrayList<>(slices.length); + int segmentsCount = 0; + for (IndexSearcher.LeafSlice slice : slices) { + segmentsCount += slice.leaves.length; + tasks.add( + new FutureTask<>( + () -> { + TopDocs[] results = new TopDocs[slice.leaves.length]; + int i = 0; + for (LeafReaderContext context : slice.leaves) { + results[i++] = searchLeaf(context, filterWeight); + } + return results; + })); + } + + sliceExecutor.invokeAll(tasks); + + TopDocs[] topDocs = new TopDocs[segmentsCount]; + int i = 0; + for (FutureTask task : tasks) { + try { + for (TopDocs docs : task.get()) { + topDocs[i++] = docs; + } + } catch (ExecutionException e) { + throw new RuntimeException(e.getCause()); + } catch (InterruptedException e) { + throw new ThreadInterruptedException(e); + } + } + return topDocs; + } + private TopDocs searchLeaf(LeafReaderContext ctx, Weight filterWeight) throws IOException { + TopDocs results = getLeafResults(ctx, filterWeight); + if (ctx.docBase > 0) { + for (ScoreDoc scoreDoc : results.scoreDocs) { + scoreDoc.doc += ctx.docBase; + } + } + return results; + } + + private TopDocs getLeafResults(LeafReaderContext ctx, Weight filterWeight) throws IOException { Bits liveDocs = ctx.reader().getLiveDocs(); int maxDoc = ctx.reader().maxDoc(); diff --git a/lucene/core/src/java/org/apache/lucene/search/BlendedTermQuery.java b/lucene/core/src/java/org/apache/lucene/search/BlendedTermQuery.java index 8b73eb5b27a9..2c7e41ac9719 100644 --- a/lucene/core/src/java/org/apache/lucene/search/BlendedTermQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/BlendedTermQuery.java @@ -19,7 +19,6 @@ import java.io.IOException; import java.util.Arrays; import java.util.List; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexReaderContext; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.Term; @@ -268,11 +267,12 @@ public String toString(String field) { } @Override - public final Query rewrite(IndexReader reader) throws IOException { + public final Query rewrite(IndexSearcher indexSearcher) throws IOException { final TermStates[] contexts = ArrayUtil.copyOfSubArray(this.contexts, 0, this.contexts.length); for (int i = 0; i < contexts.length; ++i) { - if (contexts[i] == null || contexts[i].wasBuiltFor(reader.getContext()) == false) { - contexts[i] = TermStates.build(reader.getContext(), terms[i], true); + if (contexts[i] == null + || contexts[i].wasBuiltFor(indexSearcher.getTopReaderContext()) == false) { + contexts[i] = TermStates.build(indexSearcher.getTopReaderContext(), terms[i], true); } } @@ -287,7 +287,7 @@ public final Query rewrite(IndexReader reader) throws IOException { } for (int i = 0; i < contexts.length; ++i) { - contexts[i] = adjustFrequencies(reader.getContext(), contexts[i], df, ttf); + contexts[i] = adjustFrequencies(indexSearcher.getTopReaderContext(), contexts[i], df, ttf); } Query[] termQueries = new Query[terms.length]; diff --git a/lucene/core/src/java/org/apache/lucene/search/BooleanQuery.java b/lucene/core/src/java/org/apache/lucene/search/BooleanQuery.java index f5c69621b15c..07823ae5c4d7 100644 --- a/lucene/core/src/java/org/apache/lucene/search/BooleanQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/BooleanQuery.java @@ -30,7 +30,6 @@ import java.util.Objects; import java.util.Set; import java.util.function.Predicate; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.search.BooleanClause.Occur; /** @@ -247,7 +246,7 @@ public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float bo } @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { if (clauses.size() == 0) { return new MatchNoDocsQuery("empty BooleanQuery"); } @@ -286,12 +285,12 @@ public Query rewrite(IndexReader reader) throws IOException { Query rewritten; if (occur == Occur.FILTER || occur == Occur.MUST_NOT) { // Clauses that are not involved in scoring can get some extra simplifications - rewritten = new ConstantScoreQuery(query).rewrite(reader); + rewritten = new ConstantScoreQuery(query).rewrite(indexSearcher); if (rewritten instanceof ConstantScoreQuery) { rewritten = ((ConstantScoreQuery) rewritten).getQuery(); } } else { - rewritten = query.rewrite(reader); + rewritten = query.rewrite(indexSearcher); } if (rewritten != query || query.getClass() == MatchNoDocsQuery.class) { // rewrite clause @@ -566,7 +565,7 @@ public Query rewrite(IndexReader reader) throws IOException { } } - return super.rewrite(reader); + return super.rewrite(indexSearcher); } @Override diff --git a/lucene/core/src/java/org/apache/lucene/search/BoostQuery.java b/lucene/core/src/java/org/apache/lucene/search/BoostQuery.java index 47c0f5f6f285..375269637000 100644 --- a/lucene/core/src/java/org/apache/lucene/search/BoostQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/BoostQuery.java @@ -18,7 +18,6 @@ import java.io.IOException; import java.util.Objects; -import org.apache.lucene.index.IndexReader; /** * A {@link Query} wrapper that allows to give a boost to the wrapped query. Boost values that are @@ -73,8 +72,8 @@ public int hashCode() { } @Override - public Query rewrite(IndexReader reader) throws IOException { - final Query rewritten = query.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + final Query rewritten = query.rewrite(indexSearcher); if (boost == 1f) { return rewritten; @@ -99,7 +98,7 @@ public Query rewrite(IndexReader reader) throws IOException { return new BoostQuery(rewritten, boost); } - return super.rewrite(reader); + return super.rewrite(indexSearcher); } @Override diff --git a/lucene/core/src/java/org/apache/lucene/search/CollectionTerminatedException.java b/lucene/core/src/java/org/apache/lucene/search/CollectionTerminatedException.java index 2a7e04447481..89f14fff20bc 100644 --- a/lucene/core/src/java/org/apache/lucene/search/CollectionTerminatedException.java +++ b/lucene/core/src/java/org/apache/lucene/search/CollectionTerminatedException.java @@ -31,4 +31,10 @@ public final class CollectionTerminatedException extends RuntimeException { public CollectionTerminatedException() { super(); } + + @Override + public Throwable fillInStackTrace() { + // never re-thrown so we can save the expensive stacktrace + return this; + } } diff --git a/lucene/core/src/java/org/apache/lucene/search/ConjunctionDISI.java b/lucene/core/src/java/org/apache/lucene/search/ConjunctionDISI.java index b70224f1ec50..03091b748b1c 100644 --- a/lucene/core/src/java/org/apache/lucene/search/ConjunctionDISI.java +++ b/lucene/core/src/java/org/apache/lucene/search/ConjunctionDISI.java @@ -20,7 +20,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.Comparator; import java.util.List; import org.apache.lucene.util.ArrayUtil; import org.apache.lucene.util.BitSet; @@ -99,20 +98,22 @@ static DocIdSetIterator createConjunction( allIterators.size() > 0 ? allIterators.get(0).docID() : twoPhaseIterators.get(0).approximation.docID(); - boolean iteratorsOnTheSameDoc = allIterators.stream().allMatch(it -> it.docID() == curDoc); - iteratorsOnTheSameDoc = - iteratorsOnTheSameDoc - && twoPhaseIterators.stream().allMatch(it -> it.approximation().docID() == curDoc); - if (iteratorsOnTheSameDoc == false) { - throw new IllegalArgumentException( - "Sub-iterators of ConjunctionDISI are not on the same document!"); + long minCost = Long.MAX_VALUE; + for (DocIdSetIterator allIterator : allIterators) { + if (allIterator.docID() != curDoc) { + throwSubIteratorsNotOnSameDocument(); + } + minCost = Math.min(allIterator.cost(), minCost); + } + for (TwoPhaseIterator it : twoPhaseIterators) { + if (it.approximation().docID() != curDoc) { + throwSubIteratorsNotOnSameDocument(); + } } - - long minCost = allIterators.stream().mapToLong(DocIdSetIterator::cost).min().getAsLong(); List bitSetIterators = new ArrayList<>(); List iterators = new ArrayList<>(); for (DocIdSetIterator iterator : allIterators) { - if (iterator.cost() > minCost && iterator instanceof BitSetIterator) { + if (iterator instanceof BitSetIterator && iterator.cost() > minCost) { // we put all bitset iterators into bitSetIterators // except if they have the minimum cost, since we need // them to lead the iteration in that case @@ -142,6 +143,11 @@ static DocIdSetIterator createConjunction( return disi; } + private static void throwSubIteratorsNotOnSameDocument() { + throw new IllegalArgumentException( + "Sub-iterators of ConjunctionDISI are not on the same document!"); + } + final DocIdSetIterator lead1, lead2; final DocIdSetIterator[] others; @@ -150,14 +156,7 @@ private ConjunctionDISI(List iterators) { // Sort the array the first time to allow the least frequent DocsEnum to // lead the matching. - CollectionUtil.timSort( - iterators, - new Comparator() { - @Override - public int compare(DocIdSetIterator o1, DocIdSetIterator o2) { - return Long.compare(o1.cost(), o2.cost()); - } - }); + CollectionUtil.timSort(iterators, (o1, o2) -> Long.compare(o1.cost(), o2.cost())); lead1 = iterators.get(0); lead2 = iterators.get(1); others = iterators.subList(2, iterators.size()).toArray(new DocIdSetIterator[0]); @@ -326,13 +325,7 @@ private ConjunctionTwoPhaseIterator( assert twoPhaseIterators.size() > 0; CollectionUtil.timSort( - twoPhaseIterators, - new Comparator() { - @Override - public int compare(TwoPhaseIterator o1, TwoPhaseIterator o2) { - return Float.compare(o1.matchCost(), o2.matchCost()); - } - }); + twoPhaseIterators, (o1, o2) -> Float.compare(o1.matchCost(), o2.matchCost())); this.twoPhaseIterators = twoPhaseIterators.toArray(new TwoPhaseIterator[twoPhaseIterators.size()]); diff --git a/lucene/core/src/java/org/apache/lucene/search/ConstantScoreQuery.java b/lucene/core/src/java/org/apache/lucene/search/ConstantScoreQuery.java index 2225cc109444..48f763e16460 100644 --- a/lucene/core/src/java/org/apache/lucene/search/ConstantScoreQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/ConstantScoreQuery.java @@ -18,7 +18,6 @@ import java.io.IOException; import java.util.Objects; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.util.Bits; @@ -40,8 +39,9 @@ public Query getQuery() { } @Override - public Query rewrite(IndexReader reader) throws IOException { - Query rewritten = query.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + + Query rewritten = query.rewrite(indexSearcher); // Do some extra simplifications that are legal since scores are not needed on the wrapped // query. @@ -70,7 +70,7 @@ public Query rewrite(IndexReader reader) throws IOException { return new ConstantScoreQuery(((BoostQuery) rewritten).getQuery()); } - return super.rewrite(reader); + return super.rewrite(indexSearcher); } @Override diff --git a/lucene/core/src/java/org/apache/lucene/search/DisjunctionMaxQuery.java b/lucene/core/src/java/org/apache/lucene/search/DisjunctionMaxQuery.java index 8c41c0a37cf0..1ab4f3b50818 100644 --- a/lucene/core/src/java/org/apache/lucene/search/DisjunctionMaxQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/DisjunctionMaxQuery.java @@ -23,7 +23,6 @@ import java.util.Iterator; import java.util.List; import java.util.Objects; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; /** @@ -209,11 +208,10 @@ public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float bo /** * Optimize our representation and our subqueries representations * - * @param reader the IndexReader we query * @return an optimized copy of us (which may not be a copy if there is nothing to optimize) */ @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { if (disjuncts.isEmpty()) { return new MatchNoDocsQuery("empty DisjunctionMaxQuery"); } @@ -233,7 +231,7 @@ public Query rewrite(IndexReader reader) throws IOException { boolean actuallyRewritten = false; List rewrittenDisjuncts = new ArrayList<>(); for (Query sub : disjuncts) { - Query rewrittenSub = sub.rewrite(reader); + Query rewrittenSub = sub.rewrite(indexSearcher); actuallyRewritten |= rewrittenSub != sub; rewrittenDisjuncts.add(rewrittenSub); } @@ -242,7 +240,7 @@ public Query rewrite(IndexReader reader) throws IOException { return new DisjunctionMaxQuery(rewrittenDisjuncts, tieBreakerMultiplier); } - return super.rewrite(reader); + return super.rewrite(indexSearcher); } @Override diff --git a/lucene/core/src/java/org/apache/lucene/search/DoubleValuesSource.java b/lucene/core/src/java/org/apache/lucene/search/DoubleValuesSource.java index 303dc516af8a..f27b791dd95a 100644 --- a/lucene/core/src/java/org/apache/lucene/search/DoubleValuesSource.java +++ b/lucene/core/src/java/org/apache/lucene/search/DoubleValuesSource.java @@ -22,7 +22,6 @@ import java.util.function.DoubleToLongFunction; import java.util.function.LongToDoubleFunction; import org.apache.lucene.index.DocValues; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.NumericDocValues; import org.apache.lucene.search.comparators.DoubleComparator; @@ -85,7 +84,7 @@ public Explanation explain(LeafReaderContext ctx, int docId, Explanation scoreEx * *

Queries that use DoubleValuesSource objects should call rewrite() during {@link * Query#createWeight(IndexSearcher, ScoreMode, float)} rather than during {@link - * Query#rewrite(IndexReader)} to avoid IndexReader reference leakage. + * Query#rewrite(IndexSearcher)} to avoid IndexReader reference leakage. * *

For the same reason, implementations that cache references to the IndexSearcher should * return a new object from this method. diff --git a/lucene/core/src/java/org/apache/lucene/search/FieldExistsQuery.java b/lucene/core/src/java/org/apache/lucene/search/FieldExistsQuery.java index 98c65b9ddd66..3d78df8e07c3 100644 --- a/lucene/core/src/java/org/apache/lucene/search/FieldExistsQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/FieldExistsQuery.java @@ -108,7 +108,8 @@ public int hashCode() { } @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + IndexReader reader = indexSearcher.getIndexReader(); boolean allReadersRewritable = true; for (LeafReaderContext context : reader.leaves()) { @@ -172,7 +173,7 @@ public Query rewrite(IndexReader reader) throws IOException { if (allReadersRewritable) { return new MatchAllDocsQuery(); } - return super.rewrite(reader); + return super.rewrite(indexSearcher); } @Override diff --git a/lucene/core/src/java/org/apache/lucene/search/IndexOrDocValuesQuery.java b/lucene/core/src/java/org/apache/lucene/search/IndexOrDocValuesQuery.java index 9ba52eb674f4..599608f0d842 100644 --- a/lucene/core/src/java/org/apache/lucene/search/IndexOrDocValuesQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/IndexOrDocValuesQuery.java @@ -19,7 +19,6 @@ import java.io.IOException; import org.apache.lucene.document.LongPoint; import org.apache.lucene.document.SortedNumericDocValuesField; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; /** @@ -101,9 +100,9 @@ public int hashCode() { } @Override - public Query rewrite(IndexReader reader) throws IOException { - Query indexRewrite = indexQuery.rewrite(reader); - Query dvRewrite = dvQuery.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + Query indexRewrite = indexQuery.rewrite(indexSearcher); + Query dvRewrite = dvQuery.rewrite(indexSearcher); if (indexRewrite.getClass() == MatchAllDocsQuery.class || dvRewrite.getClass() == MatchAllDocsQuery.class) { return new MatchAllDocsQuery(); diff --git a/lucene/core/src/java/org/apache/lucene/search/IndexSearcher.java b/lucene/core/src/java/org/apache/lucene/search/IndexSearcher.java index 5798ea5d2cff..f167b7161123 100644 --- a/lucene/core/src/java/org/apache/lucene/search/IndexSearcher.java +++ b/lucene/core/src/java/org/apache/lucene/search/IndexSearcher.java @@ -796,9 +796,9 @@ protected void search(List leaves, Weight weight, Collector c */ public Query rewrite(Query original) throws IOException { Query query = original; - for (Query rewrittenQuery = query.rewrite(reader); + for (Query rewrittenQuery = query.rewrite(this); rewrittenQuery != query; - rewrittenQuery = query.rewrite(reader)) { + rewrittenQuery = query.rewrite(this)) { query = rewrittenQuery; } query.visit(getNumClausesCheckVisitor()); @@ -998,6 +998,10 @@ public Executor getExecutor() { return executor; } + SliceExecutor getSliceExecutor() { + return sliceExecutor; + } + /** * Thrown when an attempt is made to add more than {@link #getMaxClauseCount()} clauses. This * typically happens if a PrefixQuery, FuzzyQuery, WildcardQuery, or TermRangeQuery is expanded to diff --git a/lucene/core/src/java/org/apache/lucene/search/IndexSortSortedNumericDocValuesRangeQuery.java b/lucene/core/src/java/org/apache/lucene/search/IndexSortSortedNumericDocValuesRangeQuery.java index eb2cf562994c..b678d34192ce 100644 --- a/lucene/core/src/java/org/apache/lucene/search/IndexSortSortedNumericDocValuesRangeQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/IndexSortSortedNumericDocValuesRangeQuery.java @@ -23,7 +23,6 @@ import org.apache.lucene.document.IntPoint; import org.apache.lucene.document.LongPoint; import org.apache.lucene.index.DocValues; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.NumericDocValues; @@ -133,12 +132,12 @@ public String toString(String field) { } @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { if (lowerValue == Long.MIN_VALUE && upperValue == Long.MAX_VALUE) { return new FieldExistsQuery(field); } - Query rewrittenFallback = fallbackQuery.rewrite(reader); + Query rewrittenFallback = fallbackQuery.rewrite(indexSearcher); if (rewrittenFallback.getClass() == MatchAllDocsQuery.class) { return new MatchAllDocsQuery(); } diff --git a/lucene/core/src/java/org/apache/lucene/search/KnnByteVectorQuery.java b/lucene/core/src/java/org/apache/lucene/search/KnnByteVectorQuery.java index 4ec617c24470..10345cd7adf4 100644 --- a/lucene/core/src/java/org/apache/lucene/search/KnnByteVectorQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/KnnByteVectorQuery.java @@ -71,7 +71,7 @@ public KnnByteVectorQuery(String field, byte[] target, int k) { */ public KnnByteVectorQuery(String field, byte[] target, int k, Query filter) { super(field, k, filter); - this.target = target; + this.target = Objects.requireNonNull(target, "target"); } @Override diff --git a/lucene/core/src/java/org/apache/lucene/search/KnnFloatVectorQuery.java b/lucene/core/src/java/org/apache/lucene/search/KnnFloatVectorQuery.java index 2b1b3a69582e..3036e7c45162 100644 --- a/lucene/core/src/java/org/apache/lucene/search/KnnFloatVectorQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/KnnFloatVectorQuery.java @@ -18,6 +18,7 @@ import java.io.IOException; import java.util.Arrays; +import java.util.Objects; import org.apache.lucene.codecs.KnnVectorsReader; import org.apache.lucene.document.KnnFloatVectorField; import org.apache.lucene.index.FieldInfo; @@ -25,6 +26,7 @@ import org.apache.lucene.index.VectorEncoding; import org.apache.lucene.util.ArrayUtil; import org.apache.lucene.util.Bits; +import org.apache.lucene.util.VectorUtil; /** * Uses {@link KnnVectorsReader#search(String, float[], int, Bits, int)} to perform nearest @@ -70,7 +72,7 @@ public KnnFloatVectorQuery(String field, float[] target, int k) { */ public KnnFloatVectorQuery(String field, float[] target, int k, Query filter) { super(field, k, filter); - this.target = target; + this.target = VectorUtil.checkFinite(Objects.requireNonNull(target, "target")); } @Override diff --git a/lucene/core/src/java/org/apache/lucene/search/MultiPhraseQuery.java b/lucene/core/src/java/org/apache/lucene/search/MultiPhraseQuery.java index 1bf34569c395..27819235f644 100644 --- a/lucene/core/src/java/org/apache/lucene/search/MultiPhraseQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/MultiPhraseQuery.java @@ -24,7 +24,6 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexReaderContext; import org.apache.lucene.index.LeafReader; import org.apache.lucene.index.LeafReaderContext; @@ -185,7 +184,7 @@ public int[] getPositions() { } @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { if (termArrays.length == 0) { return new MatchNoDocsQuery("empty MultiPhraseQuery"); } else if (termArrays.length == 1) { // optimize one-term case @@ -196,7 +195,7 @@ public Query rewrite(IndexReader reader) throws IOException { } return builder.build(); } else { - return super.rewrite(reader); + return super.rewrite(indexSearcher); } } diff --git a/lucene/core/src/java/org/apache/lucene/search/MultiTermQuery.java b/lucene/core/src/java/org/apache/lucene/search/MultiTermQuery.java index 0dc6671dcccb..44bd4279aba2 100644 --- a/lucene/core/src/java/org/apache/lucene/search/MultiTermQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/MultiTermQuery.java @@ -18,9 +18,9 @@ import java.io.IOException; import java.util.Objects; -import org.apache.lucene.index.FilteredTermsEnum; // javadocs +import org.apache.lucene.index.FilteredTermsEnum; import org.apache.lucene.index.IndexReader; -import org.apache.lucene.index.SingleTermsEnum; // javadocs +import org.apache.lucene.index.SingleTermsEnum; import org.apache.lucene.index.Term; import org.apache.lucene.index.TermStates; import org.apache.lucene.index.Terms; @@ -321,8 +321,8 @@ public long getTermsCount() throws IOException { * AttributeSource)}. For example, to rewrite to a single term, return a {@link SingleTermsEnum} */ @Override - public final Query rewrite(IndexReader reader) throws IOException { - return rewriteMethod.rewrite(reader, this); + public final Query rewrite(IndexSearcher indexSearcher) throws IOException { + return rewriteMethod.rewrite(indexSearcher.getIndexReader(), this); } public RewriteMethod getRewriteMethod() { diff --git a/lucene/core/src/java/org/apache/lucene/search/NGramPhraseQuery.java b/lucene/core/src/java/org/apache/lucene/search/NGramPhraseQuery.java index 41b0decba7c7..e5023bf032d6 100644 --- a/lucene/core/src/java/org/apache/lucene/search/NGramPhraseQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/NGramPhraseQuery.java @@ -18,14 +18,13 @@ import java.io.IOException; import java.util.Objects; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.Term; /** * This is a {@link PhraseQuery} which is optimized for n-gram phrase query. For example, when you * query "ABCD" on a 2-gram field, you may want to use NGramPhraseQuery rather than {@link - * PhraseQuery}, because NGramPhraseQuery will {@link #rewrite(IndexReader)} the query to "AB/0 - * CD/2", while {@link PhraseQuery} will query "AB/0 BC/1 CD/2" (where term/position). + * PhraseQuery}, because NGramPhraseQuery will {@link Query#rewrite(IndexSearcher)} the query to + * "AB/0 CD/2", while {@link PhraseQuery} will query "AB/0 BC/1 CD/2" (where term/position). */ public class NGramPhraseQuery extends Query { @@ -44,7 +43,7 @@ public NGramPhraseQuery(int n, PhraseQuery query) { } @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { final Term[] terms = phraseQuery.getTerms(); final int[] positions = phraseQuery.getPositions(); @@ -63,7 +62,7 @@ public Query rewrite(IndexReader reader) throws IOException { } if (isOptimizable == false) { - return phraseQuery.rewrite(reader); + return phraseQuery.rewrite(indexSearcher); } PhraseQuery.Builder builder = new PhraseQuery.Builder(); diff --git a/lucene/core/src/java/org/apache/lucene/search/NamedMatches.java b/lucene/core/src/java/org/apache/lucene/search/NamedMatches.java index 9a24f9433bae..d0ec5c3a2124 100644 --- a/lucene/core/src/java/org/apache/lucene/search/NamedMatches.java +++ b/lucene/core/src/java/org/apache/lucene/search/NamedMatches.java @@ -25,7 +25,6 @@ import java.util.LinkedList; import java.util.List; import java.util.Objects; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; /** @@ -113,8 +112,8 @@ public Matches matches(LeafReaderContext context, int doc) throws IOException { } @Override - public Query rewrite(IndexReader reader) throws IOException { - Query rewritten = in.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + Query rewritten = in.rewrite(indexSearcher); if (rewritten != in) { return new NamedQuery(name, rewritten); } diff --git a/lucene/core/src/java/org/apache/lucene/search/PhraseQuery.java b/lucene/core/src/java/org/apache/lucene/search/PhraseQuery.java index 93a2ace64531..643861651367 100644 --- a/lucene/core/src/java/org/apache/lucene/search/PhraseQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/PhraseQuery.java @@ -24,7 +24,6 @@ import org.apache.lucene.codecs.lucene90.Lucene90PostingsFormat; import org.apache.lucene.codecs.lucene90.Lucene90PostingsReader; import org.apache.lucene.index.ImpactsEnum; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexReaderContext; import org.apache.lucene.index.LeafReader; import org.apache.lucene.index.LeafReaderContext; @@ -284,7 +283,7 @@ public int[] getPositions() { } @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { if (terms.length == 0) { return new MatchNoDocsQuery("empty PhraseQuery"); } else if (terms.length == 1) { @@ -296,7 +295,7 @@ public Query rewrite(IndexReader reader) throws IOException { } return new PhraseQuery(slop, terms, newPositions); } else { - return super.rewrite(reader); + return super.rewrite(indexSearcher); } } diff --git a/lucene/core/src/java/org/apache/lucene/search/Query.java b/lucene/core/src/java/org/apache/lucene/search/Query.java index 4f04728395d9..c872c076b76f 100644 --- a/lucene/core/src/java/org/apache/lucene/search/Query.java +++ b/lucene/core/src/java/org/apache/lucene/search/Query.java @@ -17,7 +17,10 @@ package org.apache.lucene.search; import java.io.IOException; +import java.security.AccessController; +import java.security.PrivilegedAction; import org.apache.lucene.index.IndexReader; +import org.apache.lucene.util.VirtualMethod; /** * The abstract base class for queries. @@ -41,10 +44,21 @@ * * *

See also additional queries available in the Queries module + * href="{@docRoot}/../queries/overview-summary.html">Queries module. */ public abstract class Query { + private static final VirtualMethod oldMethod = + new VirtualMethod<>(Query.class, "rewrite", IndexReader.class); + private static final VirtualMethod newMethod = + new VirtualMethod<>(Query.class, "rewrite", IndexSearcher.class); + private final boolean isDeprecatedRewriteMethodOverridden = + AccessController.doPrivileged( + (PrivilegedAction) + () -> + VirtualMethod.compareImplementationDistance(this.getClass(), oldMethod, newMethod) + > 0); + /** * Prints a query to a string, with field assumed to be the default field and * omitted. @@ -77,14 +91,36 @@ public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float bo *

Callers are expected to call rewrite multiple times if necessary, until the * rewritten query is the same as the original query. * + * @deprecated Use {@link Query#rewrite(IndexSearcher)} * @see IndexSearcher#rewrite(Query) */ + @Deprecated public Query rewrite(IndexReader reader) throws IOException { - return this; + return isDeprecatedRewriteMethodOverridden ? this : rewrite(new IndexSearcher(reader)); + } + + /** + * Expert: called to re-write queries into primitive queries. For example, a PrefixQuery will be + * rewritten into a BooleanQuery that consists of TermQuerys. + * + *

Callers are expected to call rewrite multiple times if necessary, until the + * rewritten query is the same as the original query. + * + *

The rewrite process may be able to make use of IndexSearcher's executor and be executed in + * parallel if the executor is provided. + * + *

However, if any of the intermediary queries do not satisfy the new API, parallel rewrite is + * not possible for any subsequent sub-queries. To take advantage of this API, the entire query + * tree must override this method. + * + * @see IndexSearcher#rewrite(Query) + */ + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + return isDeprecatedRewriteMethodOverridden ? rewrite(indexSearcher.getIndexReader()) : this; } /** - * Recurse through the query tree, visiting any child queries + * Recurse through the query tree, visiting any child queries. * * @param visitor a QueryVisitor to be called by each query in the tree */ @@ -95,8 +131,8 @@ public Query rewrite(IndexReader reader) throws IOException { * that {@link QueryCache} works properly. * *

Typically a query will be equal to another only if it's an instance of the same class and - * its document-filtering properties are identical that other instance. Utility methods are - * provided for certain repetitive code. + * its document-filtering properties are identical to those of the other instance. Utility methods + * are provided for certain repetitive code. * * @see #sameClassAs(Object) * @see #classHash() @@ -119,7 +155,7 @@ public Query rewrite(IndexReader reader) throws IOException { * *

When this method is used in an implementation of {@link #equals(Object)}, consider using * {@link #classHash()} in the implementation of {@link #hashCode} to differentiate different - * class + * class. */ protected final boolean sameClassAs(Object other) { return other != null && getClass() == other.getClass(); diff --git a/lucene/core/src/java/org/apache/lucene/search/QueueSizeBasedExecutor.java b/lucene/core/src/java/org/apache/lucene/search/QueueSizeBasedExecutor.java index a76b81f5da19..65ba1ea5573d 100644 --- a/lucene/core/src/java/org/apache/lucene/search/QueueSizeBasedExecutor.java +++ b/lucene/core/src/java/org/apache/lucene/search/QueueSizeBasedExecutor.java @@ -17,7 +17,6 @@ package org.apache.lucene.search; -import java.util.Collection; import java.util.concurrent.ThreadPoolExecutor; /** @@ -30,31 +29,15 @@ class QueueSizeBasedExecutor extends SliceExecutor { private final ThreadPoolExecutor threadPoolExecutor; - public QueueSizeBasedExecutor(ThreadPoolExecutor threadPoolExecutor) { + QueueSizeBasedExecutor(ThreadPoolExecutor threadPoolExecutor) { super(threadPoolExecutor); this.threadPoolExecutor = threadPoolExecutor; } @Override - public void invokeAll(Collection tasks) { - int i = 0; - - for (Runnable task : tasks) { - boolean shouldExecuteOnCallerThread = false; - - // Execute last task on caller thread - if (i == tasks.size() - 1) { - shouldExecuteOnCallerThread = true; - } - - if (threadPoolExecutor.getQueue().size() - >= (threadPoolExecutor.getMaximumPoolSize() * LIMITING_FACTOR)) { - shouldExecuteOnCallerThread = true; - } - - processTask(task, shouldExecuteOnCallerThread); - - ++i; - } + boolean shouldExecuteOnCallerThread(int index, int numTasks) { + return super.shouldExecuteOnCallerThread(index, numTasks) + || threadPoolExecutor.getQueue().size() + >= (threadPoolExecutor.getMaximumPoolSize() * LIMITING_FACTOR); } } diff --git a/lucene/core/src/java/org/apache/lucene/search/ScoringRewrite.java b/lucene/core/src/java/org/apache/lucene/search/ScoringRewrite.java index debc3efae154..5873b83075b6 100644 --- a/lucene/core/src/java/org/apache/lucene/search/ScoringRewrite.java +++ b/lucene/core/src/java/org/apache/lucene/search/ScoringRewrite.java @@ -101,8 +101,7 @@ public Query rewrite(IndexReader reader, MultiTermQuery query) throws IOExceptio protected abstract void checkMaxClauseCount(int count) throws IOException; @Override - public final Query rewrite(final IndexReader reader, final MultiTermQuery query) - throws IOException { + public final Query rewrite(IndexReader reader, final MultiTermQuery query) throws IOException { final B builder = getTopLevelBuilder(); final ParallelArraysTermCollector col = new ParallelArraysTermCollector(); collectTerms(reader, query, col); diff --git a/lucene/core/src/java/org/apache/lucene/search/SliceExecutor.java b/lucene/core/src/java/org/apache/lucene/search/SliceExecutor.java index c84beeb5fb78..0e593740914d 100644 --- a/lucene/core/src/java/org/apache/lucene/search/SliceExecutor.java +++ b/lucene/core/src/java/org/apache/lucene/search/SliceExecutor.java @@ -18,6 +18,7 @@ package org.apache.lucene.search; import java.util.Collection; +import java.util.Objects; import java.util.concurrent.Executor; import java.util.concurrent.RejectedExecutionException; @@ -28,54 +29,30 @@ class SliceExecutor { private final Executor executor; - public SliceExecutor(Executor executor) { - this.executor = executor; + SliceExecutor(Executor executor) { + this.executor = Objects.requireNonNull(executor, "Executor is null"); } - public void invokeAll(Collection tasks) { - - if (tasks == null) { - throw new IllegalArgumentException("Tasks is null"); - } - - if (executor == null) { - throw new IllegalArgumentException("Executor is null"); - } - + final void invokeAll(Collection tasks) { int i = 0; - for (Runnable task : tasks) { - boolean shouldExecuteOnCallerThread = false; - - // Execute last task on caller thread - if (i == tasks.size() - 1) { - shouldExecuteOnCallerThread = true; + if (shouldExecuteOnCallerThread(i, tasks.size())) { + task.run(); + } else { + try { + executor.execute(task); + } catch ( + @SuppressWarnings("unused") + RejectedExecutionException e) { + task.run(); + } } - - processTask(task, shouldExecuteOnCallerThread); ++i; } - ; } - // Helper method to execute a single task - protected void processTask(final Runnable task, final boolean shouldExecuteOnCallerThread) { - if (task == null) { - throw new IllegalArgumentException("Input is null"); - } - - if (!shouldExecuteOnCallerThread) { - try { - executor.execute(task); - - return; - } catch ( - @SuppressWarnings("unused") - RejectedExecutionException e) { - // Execute on caller thread - } - } - - task.run(); + boolean shouldExecuteOnCallerThread(int index, int numTasks) { + // Execute last task on caller thread + return index == numTasks - 1; } } diff --git a/lucene/core/src/java/org/apache/lucene/search/SynonymQuery.java b/lucene/core/src/java/org/apache/lucene/search/SynonymQuery.java index 8131c879d3e9..7e314870f9c7 100644 --- a/lucene/core/src/java/org/apache/lucene/search/SynonymQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/SynonymQuery.java @@ -29,7 +29,6 @@ import org.apache.lucene.index.Impacts; import org.apache.lucene.index.ImpactsEnum; import org.apache.lucene.index.ImpactsSource; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.PostingsEnum; import org.apache.lucene.index.SlowImpactsEnum; @@ -114,7 +113,7 @@ public SynonymQuery build() { */ private SynonymQuery(TermAndBoost[] terms, String field) { this.terms = Objects.requireNonNull(terms); - this.field = field; + this.field = Objects.requireNonNull(field); } public List getTerms() { @@ -147,11 +146,13 @@ public int hashCode() { @Override public boolean equals(Object other) { - return sameClassAs(other) && Arrays.equals(terms, ((SynonymQuery) other).terms); + return sameClassAs(other) + && field.equals(((SynonymQuery) other).field) + && Arrays.equals(terms, ((SynonymQuery) other).terms); } @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { // optimize zero and non-boosted single term cases if (terms.length == 0) { return new BooleanQuery.Builder().build(); diff --git a/lucene/core/src/java/org/apache/lucene/search/TermInSetQuery.java b/lucene/core/src/java/org/apache/lucene/search/TermInSetQuery.java index 2e0a297c7463..ed268751bba4 100644 --- a/lucene/core/src/java/org/apache/lucene/search/TermInSetQuery.java +++ b/lucene/core/src/java/org/apache/lucene/search/TermInSetQuery.java @@ -17,11 +17,10 @@ package org.apache.lucene.search; import java.io.IOException; -import java.util.ArrayList; +import java.io.UncheckedIOException; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.List; import java.util.SortedSet; import org.apache.lucene.index.FilteredTermsEnum; import org.apache.lucene.index.PrefixCodedTerms; @@ -38,7 +37,6 @@ import org.apache.lucene.util.automaton.Automata; import org.apache.lucene.util.automaton.Automaton; import org.apache.lucene.util.automaton.ByteRunAutomaton; -import org.apache.lucene.util.automaton.CompiledAutomaton; import org.apache.lucene.util.automaton.Operations; /** @@ -150,13 +148,17 @@ public void visit(QueryVisitor visitor) { } } + // TODO: This is pretty heavy-weight. If we have TermInSetQuery directly extend AutomatonQuery + // we won't have to do this (see GH#12176). private ByteRunAutomaton asByteRunAutomaton() { - TermIterator iterator = termData.iterator(); - List automata = new ArrayList<>(); - for (BytesRef term = iterator.next(); term != null; term = iterator.next()) { - automata.add(Automata.makeBinary(term)); + try { + Automaton a = Automata.makeBinaryStringUnion(termData.iterator()); + return new ByteRunAutomaton(a, true, Operations.DEFAULT_DETERMINIZE_WORK_LIMIT); + } catch (IOException e) { + // Shouldn't happen since termData.iterator() provides an interator implementation that + // never throws: + throw new UncheckedIOException(e); } - return new CompiledAutomaton(Operations.union(automata)).runAutomaton; } @Override diff --git a/lucene/core/src/java/org/apache/lucene/search/TimeLimitingBulkScorer.java b/lucene/core/src/java/org/apache/lucene/search/TimeLimitingBulkScorer.java index 5e33884ea4ff..517f0a0e77b2 100644 --- a/lucene/core/src/java/org/apache/lucene/search/TimeLimitingBulkScorer.java +++ b/lucene/core/src/java/org/apache/lucene/search/TimeLimitingBulkScorer.java @@ -41,6 +41,12 @@ static class TimeExceededException extends RuntimeException { private TimeExceededException() { super("TimeLimit Exceeded"); } + + @Override + public Throwable fillInStackTrace() { + // never re-thrown so we can save the expensive stacktrace + return this; + } } private final BulkScorer in; diff --git a/lucene/core/src/java/org/apache/lucene/search/TimeLimitingCollector.java b/lucene/core/src/java/org/apache/lucene/search/TimeLimitingCollector.java index 4a208a3f0c5f..c50f3a372e97 100644 --- a/lucene/core/src/java/org/apache/lucene/search/TimeLimitingCollector.java +++ b/lucene/core/src/java/org/apache/lucene/search/TimeLimitingCollector.java @@ -33,9 +33,9 @@ public class TimeLimitingCollector implements Collector { /** Thrown when elapsed search time exceeds allowed search time. */ @SuppressWarnings("serial") public static class TimeExceededException extends RuntimeException { - private long timeAllowed; - private long timeElapsed; - private int lastDocCollected; + private final long timeAllowed; + private final long timeElapsed; + private final int lastDocCollected; private TimeExceededException(long timeAllowed, long timeElapsed, int lastDocCollected) { super( diff --git a/lucene/core/src/java/org/apache/lucene/search/TopTermsRewrite.java b/lucene/core/src/java/org/apache/lucene/search/TopTermsRewrite.java index 067867ca7348..b5c52ba7cedf 100644 --- a/lucene/core/src/java/org/apache/lucene/search/TopTermsRewrite.java +++ b/lucene/core/src/java/org/apache/lucene/search/TopTermsRewrite.java @@ -61,8 +61,7 @@ public int getSize() { protected abstract int getMaxSize(); @Override - public final Query rewrite(final IndexReader reader, final MultiTermQuery query) - throws IOException { + public final Query rewrite(IndexReader reader, final MultiTermQuery query) throws IOException { final int maxSize = Math.min(size, getMaxSize()); final PriorityQueue stQueue = new PriorityQueue<>(); collectTerms( diff --git a/lucene/core/src/java/org/apache/lucene/search/comparators/NumericComparator.java b/lucene/core/src/java/org/apache/lucene/search/comparators/NumericComparator.java index 0ac859d40f14..ea75530fb2b4 100644 --- a/lucene/core/src/java/org/apache/lucene/search/comparators/NumericComparator.java +++ b/lucene/core/src/java/org/apache/lucene/search/comparators/NumericComparator.java @@ -91,8 +91,8 @@ public abstract class NumericLeafComparator implements LeafFieldComparator { // if skipping functionality should be enabled on this segment private final boolean enableSkipping; private final int maxDoc; - private final byte[] minValueAsBytes; - private final byte[] maxValueAsBytes; + private byte[] minValueAsBytes; + private byte[] maxValueAsBytes; private DocIdSetIterator competitiveIterator; private long iteratorCost = -1; @@ -128,16 +128,10 @@ public NumericLeafComparator(LeafReaderContext context) throws IOException { } this.enableSkipping = true; // skipping is enabled when points are available this.maxDoc = context.reader().maxDoc(); - this.maxValueAsBytes = - reverse == false ? new byte[bytesCount] : topValueSet ? new byte[bytesCount] : null; - this.minValueAsBytes = - reverse ? new byte[bytesCount] : topValueSet ? new byte[bytesCount] : null; this.competitiveIterator = DocIdSetIterator.all(maxDoc); } else { this.enableSkipping = false; this.maxDoc = 0; - this.maxValueAsBytes = null; - this.minValueAsBytes = null; } } @@ -191,7 +185,9 @@ public void setHitsThresholdReached() throws IOException { // update its iterator to include possibly only docs that are "stronger" than the current bottom // entry private void updateCompetitiveIterator() throws IOException { - if (enableSkipping == false || hitsThresholdReached == false || queueFull == false) return; + if (enableSkipping == false + || hitsThresholdReached == false + || (queueFull == false && topValueSet == false)) return; // if some documents have missing points, check that missing values prohibits optimization if ((pointValues.getDocCount() < maxDoc) && isMissingValueCompetitive()) { return; // we can't filter out documents, as documents with missing values are competitive @@ -204,13 +200,21 @@ private void updateCompetitiveIterator() throws IOException { return; } if (reverse == false) { - encodeBottom(maxValueAsBytes); + if (queueFull) { // bottom is avilable only when queue is full + maxValueAsBytes = maxValueAsBytes == null ? new byte[bytesCount] : maxValueAsBytes; + encodeBottom(maxValueAsBytes); + } if (topValueSet) { + minValueAsBytes = minValueAsBytes == null ? new byte[bytesCount] : minValueAsBytes; encodeTop(minValueAsBytes); } } else { - encodeBottom(minValueAsBytes); + if (queueFull) { // bottom is avilable only when queue is full + minValueAsBytes = minValueAsBytes == null ? new byte[bytesCount] : minValueAsBytes; + encodeBottom(minValueAsBytes); + } if (topValueSet) { + maxValueAsBytes = maxValueAsBytes == null ? new byte[bytesCount] : maxValueAsBytes; encodeTop(maxValueAsBytes); } } diff --git a/lucene/core/src/java/org/apache/lucene/search/package-info.java b/lucene/core/src/java/org/apache/lucene/search/package-info.java index 4f606597d0a3..31a9d4018c8f 100644 --- a/lucene/core/src/java/org/apache/lucene/search/package-info.java +++ b/lucene/core/src/java/org/apache/lucene/search/package-info.java @@ -357,11 +357,11 @@ * each Query implementation must provide an implementation of Weight. See the subsection on * The Weight Interface below for details on implementing the * Weight interface. - *

  • {@link org.apache.lucene.search.Query#rewrite(org.apache.lucene.index.IndexReader) - * rewrite(IndexReader reader)} — Rewrites queries into primitive queries. Primitive - * queries are: {@link org.apache.lucene.search.TermQuery TermQuery}, {@link - * org.apache.lucene.search.BooleanQuery BooleanQuery}, and other queries that - * implement {@link org.apache.lucene.search.Query#createWeight(IndexSearcher,ScoreMode,float) + *
  • {@link org.apache.lucene.search.Query#rewrite(IndexSearcher) rewrite(IndexSearcher + * searcher)} — Rewrites queries into primitive queries. Primitive queries are: {@link + * org.apache.lucene.search.TermQuery TermQuery}, {@link org.apache.lucene.search.BooleanQuery + * BooleanQuery}, and other queries that implement {@link + * org.apache.lucene.search.Query#createWeight(IndexSearcher,ScoreMode,float) * createWeight(IndexSearcher searcher,ScoreMode scoreMode, float boost)} * * diff --git a/lucene/core/src/java/org/apache/lucene/store/BufferedIndexInput.java b/lucene/core/src/java/org/apache/lucene/store/BufferedIndexInput.java index 974ad0c68747..442dbd7af422 100644 --- a/lucene/core/src/java/org/apache/lucene/store/BufferedIndexInput.java +++ b/lucene/core/src/java/org/apache/lucene/store/BufferedIndexInput.java @@ -43,7 +43,7 @@ public abstract class BufferedIndexInput extends IndexInput implements RandomAcc /** A buffer size for merges set to {@value #MERGE_BUFFER_SIZE}. */ public static final int MERGE_BUFFER_SIZE = 4096; - private int bufferSize = BUFFER_SIZE; + private final int bufferSize; private ByteBuffer buffer = EMPTY_BYTEBUFFER; @@ -72,7 +72,7 @@ public BufferedIndexInput(String resourceDesc, int bufferSize) { this.bufferSize = bufferSize; } - /** Returns buffer size. @see #setBufferSize */ + /** Returns buffer size */ public final int getBufferSize() { return bufferSize; } @@ -220,55 +220,50 @@ public final long readVLong() throws IOException { } } - @Override - public final byte readByte(long pos) throws IOException { + private long resolvePositionInBuffer(long pos, int width) throws IOException { long index = pos - bufferStart; - if (index < 0 || index >= buffer.limit()) { + if (index >= 0 && index <= buffer.limit() - width) { + return index; + } + if (index < 0) { + // if we're moving backwards, then try and fill up the previous page rather than + // starting again at the current pos, to avoid successive backwards reads reloading + // the same data over and over again. We also check that we can read `width` + // bytes without going over the end of the buffer + bufferStart = Math.max(bufferStart - bufferSize, pos + width - bufferSize); + bufferStart = Math.max(bufferStart, 0); + bufferStart = Math.min(bufferStart, pos); + } else { + // we're moving forwards, reset the buffer to start at pos bufferStart = pos; - buffer.limit(0); // trigger refill() on read - seekInternal(pos); - refill(); - index = 0; } + buffer.limit(0); // trigger refill() on read + seekInternal(bufferStart); + refill(); + return pos - bufferStart; + } + + @Override + public final byte readByte(long pos) throws IOException { + long index = resolvePositionInBuffer(pos, Byte.BYTES); return buffer.get((int) index); } @Override public final short readShort(long pos) throws IOException { - long index = pos - bufferStart; - if (index < 0 || index >= buffer.limit() - 1) { - bufferStart = pos; - buffer.limit(0); // trigger refill() on read - seekInternal(pos); - refill(); - index = 0; - } + long index = resolvePositionInBuffer(pos, Short.BYTES); return buffer.getShort((int) index); } @Override public final int readInt(long pos) throws IOException { - long index = pos - bufferStart; - if (index < 0 || index >= buffer.limit() - 3) { - bufferStart = pos; - buffer.limit(0); // trigger refill() on read - seekInternal(pos); - refill(); - index = 0; - } + long index = resolvePositionInBuffer(pos, Integer.BYTES); return buffer.getInt((int) index); } @Override public final long readLong(long pos) throws IOException { - long index = pos - bufferStart; - if (index < 0 || index >= buffer.limit() - 7) { - bufferStart = pos; - buffer.limit(0); // trigger refill() on read - seekInternal(pos); - refill(); - index = 0; - } + long index = resolvePositionInBuffer(pos, Long.BYTES); return buffer.getLong((int) index); } diff --git a/lucene/core/src/java/org/apache/lucene/store/ByteBufferGuard.java b/lucene/core/src/java/org/apache/lucene/store/ByteBufferGuard.java index 2d75597f9deb..a9e65ffa06c2 100644 --- a/lucene/core/src/java/org/apache/lucene/store/ByteBufferGuard.java +++ b/lucene/core/src/java/org/apache/lucene/store/ByteBufferGuard.java @@ -17,11 +17,11 @@ package org.apache.lucene.store; import java.io.IOException; +import java.lang.invoke.VarHandle; import java.nio.ByteBuffer; import java.nio.FloatBuffer; import java.nio.IntBuffer; import java.nio.LongBuffer; -import java.util.concurrent.atomic.AtomicInteger; /** * A guard that is created for every {@link ByteBufferIndexInput} that tries on best effort to @@ -49,9 +49,6 @@ static interface BufferCleaner { /** Not volatile; see comments on visibility below! */ private boolean invalidated = false; - /** Used as a store-store barrier; see comments below! */ - private final AtomicInteger barrier = new AtomicInteger(); - /** * Creates an instance to be used for a single {@link ByteBufferIndexInput} which must be shared * by all of its clones. @@ -69,10 +66,9 @@ public void invalidateAndUnmap(ByteBuffer... bufs) throws IOException { // the "invalidated" field update visible to other threads. We specifically // don't make "invalidated" field volatile for performance reasons, hoping the // JVM won't optimize away reads of that field and hardware should ensure - // caches are in sync after this call. This isn't entirely "fool-proof" - // (see LUCENE-7409 discussion), but it has been shown to work in practice - // and we count on this behavior. - barrier.lazySet(0); + // caches are in sync after this call. + // For previous implementation (based on `AtomicInteger#lazySet(0)`) see LUCENE-7409. + VarHandle.fullFence(); // we give other threads a bit of time to finish reads on their ByteBuffer...: Thread.yield(); // finally unmap the ByteBuffers: diff --git a/lucene/core/src/java/org/apache/lucene/store/MMapDirectory.java b/lucene/core/src/java/org/apache/lucene/store/MMapDirectory.java index 5d23fb2f1ae0..30acb7023f03 100644 --- a/lucene/core/src/java/org/apache/lucene/store/MMapDirectory.java +++ b/lucene/core/src/java/org/apache/lucene/store/MMapDirectory.java @@ -76,9 +76,9 @@ *
  • {@code permission java.lang.RuntimePermission "accessClassInPackage.sun.misc";} * * - *

    On exactly Java 19 this class will use the modern {@code MemorySegment} API which - * allows to safely unmap (if you discover any problems with this preview API, you can disable it by - * using system property {@link #ENABLE_MEMORY_SEGMENTS_SYSPROP}). + *

    On exactly Java 19 / 20 / 21 this class will use the modern {@code MemorySegment} API + * which allows to safely unmap (if you discover any problems with this preview API, you can disable + * it by using system property {@link #ENABLE_MEMORY_SEGMENTS_SYSPROP}). * *

    NOTE: Accessing this class either directly or indirectly from a thread while it's * interrupted can close the underlying channel immediately if at the same time the thread is @@ -123,7 +123,7 @@ public class MMapDirectory extends FSDirectory { * Default max chunk size: * *

      - *
    • 16 GiBytes for 64 bit Java 19 JVMs + *
    • 16 GiBytes for 64 bit Java 19 / 20 / 21 JVMs *
    • 1 GiBytes for other 64 bit JVMs *
    • 256 MiBytes for 32 bit JVMs *
    @@ -220,9 +220,9 @@ public MMapDirectory(Path path, LockFactory lockFactory, int maxChunkSize) throw * files cannot be mapped. Using a lower chunk size makes the directory implementation a little * bit slower (as the correct chunk may be resolved on lots of seeks) but the chance is higher * that mmap does not fail. On 64 bit Java platforms, this parameter should always be large (like - * 1 GiBytes, or even larger with Java 19), as the address space is big enough. If it is larger, - * fragmentation of address space increases, but number of file handles and mappings is lower for - * huge installations with many open indexes. + * 1 GiBytes, or even larger with recent Java versions), as the address space is big enough. If it + * is larger, fragmentation of address space increases, but number of file handles and mappings is + * lower for huge installations with many open indexes. * *

    Please note: The chunk size is always rounded down to a power of 2. * @@ -417,7 +417,7 @@ private static MMapIndexInputProvider lookupProvider() { } final var lookup = MethodHandles.lookup(); final int runtimeVersion = Runtime.version().feature(); - if (runtimeVersion == 19 || runtimeVersion == 20) { + if (runtimeVersion >= 19 && runtimeVersion <= 21) { try { final var cls = lookup.findClass("org.apache.lucene.store.MemorySegmentIndexInputProvider"); // we use method handles, so we do not need to deal with setAccessible as we have private @@ -437,9 +437,9 @@ private static MMapIndexInputProvider lookupProvider() { throw new LinkageError( "MemorySegmentIndexInputProvider is missing in Lucene JAR file", cnfe); } - } else if (runtimeVersion >= 21) { + } else if (runtimeVersion >= 22) { LOG.warning( - "You are running with Java 21 or later. To make full use of MMapDirectory, please update Apache Lucene."); + "You are running with Java 22 or later. To make full use of MMapDirectory, please update Apache Lucene."); } return new MappedByteBufferIndexInputProvider(); } diff --git a/lucene/core/src/java/org/apache/lucene/util/BitSet.java b/lucene/core/src/java/org/apache/lucene/util/BitSet.java index f8b8ba65a591..c5d84833b28a 100644 --- a/lucene/core/src/java/org/apache/lucene/util/BitSet.java +++ b/lucene/core/src/java/org/apache/lucene/util/BitSet.java @@ -43,6 +43,16 @@ public static BitSet of(DocIdSetIterator it, int maxDoc) throws IOException { return set; } + /** + * Clear all the bits of the set. + * + *

    Depending on the implementation, this may be significantly faster than clear(0, length). + */ + public void clear() { + // default implementation for compatibility + clear(0, length()); + } + /** Set the bit at i. */ public abstract void set(int i); diff --git a/lucene/core/src/java/org/apache/lucene/util/FixedBitSet.java b/lucene/core/src/java/org/apache/lucene/util/FixedBitSet.java index 5566bd0c4833..ebf626a777da 100644 --- a/lucene/core/src/java/org/apache/lucene/util/FixedBitSet.java +++ b/lucene/core/src/java/org/apache/lucene/util/FixedBitSet.java @@ -147,6 +147,11 @@ public FixedBitSet(long[] storedBits, int numBits) { assert verifyGhostBitsClear(); } + @Override + public void clear() { + Arrays.fill(bits, 0L); + } + /** * Checks if the bits past numBits are clear. Some methods rely on this implicit assumption: * search for "Depends on the ghost bits being clear!" diff --git a/lucene/core/src/java/org/apache/lucene/util/SparseFixedBitSet.java b/lucene/core/src/java/org/apache/lucene/util/SparseFixedBitSet.java index 49d61614e86d..b4ebe3cfc59a 100644 --- a/lucene/core/src/java/org/apache/lucene/util/SparseFixedBitSet.java +++ b/lucene/core/src/java/org/apache/lucene/util/SparseFixedBitSet.java @@ -17,6 +17,7 @@ package org.apache.lucene.util; import java.io.IOException; +import java.util.Arrays; import org.apache.lucene.search.DocIdSetIterator; /** @@ -73,6 +74,17 @@ public SparseFixedBitSet(int length) { + RamUsageEstimator.shallowSizeOf(bits); } + @Override + public void clear() { + Arrays.fill(bits, null); + Arrays.fill(indices, 0L); + nonZeroLongCount = 0; + ramBytesUsed = + BASE_RAM_BYTES_USED + + RamUsageEstimator.sizeOf(indices) + + RamUsageEstimator.shallowSizeOf(bits); + } + @Override public int length() { return length; diff --git a/lucene/core/src/java/org/apache/lucene/util/TermAndVector.java b/lucene/core/src/java/org/apache/lucene/util/TermAndVector.java new file mode 100644 index 000000000000..1ade19a19803 --- /dev/null +++ b/lucene/core/src/java/org/apache/lucene/util/TermAndVector.java @@ -0,0 +1,72 @@ +/* + * 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.util; + +import java.util.Locale; + +/** + * Word2Vec unit composed by a term with the associated vector + * + * @lucene.experimental + */ +public class TermAndVector { + + private final BytesRef term; + private final float[] vector; + + public TermAndVector(BytesRef term, float[] vector) { + this.term = term; + this.vector = vector; + } + + public BytesRef getTerm() { + return this.term; + } + + public float[] getVector() { + return this.vector; + } + + public int size() { + return vector.length; + } + + public void normalizeVector() { + float vectorLength = 0; + for (int i = 0; i < vector.length; i++) { + vectorLength += vector[i] * vector[i]; + } + vectorLength = (float) Math.sqrt(vectorLength); + for (int i = 0; i < vector.length; i++) { + vector[i] /= vectorLength; + } + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(this.term.utf8ToString()); + builder.append(" ["); + if (vector.length > 0) { + for (int i = 0; i < vector.length - 1; i++) { + builder.append(String.format(Locale.ROOT, "%.3f,", vector[i])); + } + builder.append(String.format(Locale.ROOT, "%.3f]", vector[vector.length - 1])); + } + return builder.toString(); + } +} diff --git a/lucene/core/src/java/org/apache/lucene/util/UnicodeUtil.java b/lucene/core/src/java/org/apache/lucene/util/UnicodeUtil.java index a9e9d815eb49..9cbd4910271b 100644 --- a/lucene/core/src/java/org/apache/lucene/util/UnicodeUtil.java +++ b/lucene/core/src/java/org/apache/lucene/util/UnicodeUtil.java @@ -477,40 +477,67 @@ public static int UTF8toUTF32(final BytesRef utf8, final int[] ints) { int utf8Upto = utf8.offset; final byte[] bytes = utf8.bytes; final int utf8Limit = utf8.offset + utf8.length; + UTF8CodePoint reuse = null; while (utf8Upto < utf8Limit) { - final int numBytes = utf8CodeLength[bytes[utf8Upto] & 0xFF]; - int v = 0; - switch (numBytes) { - case 1: - ints[utf32Count++] = bytes[utf8Upto++]; - continue; - case 2: - // 5 useful bits - v = bytes[utf8Upto++] & 31; - break; - case 3: - // 4 useful bits - v = bytes[utf8Upto++] & 15; - break; - case 4: - // 3 useful bits - v = bytes[utf8Upto++] & 7; - break; - default: - throw new IllegalArgumentException("invalid utf8"); - } - - // TODO: this may read past utf8's limit. - final int limit = utf8Upto + numBytes - 1; - while (utf8Upto < limit) { - v = v << 6 | bytes[utf8Upto++] & 63; - } - ints[utf32Count++] = v; + reuse = codePointAt(bytes, utf8Upto, reuse); + ints[utf32Count++] = reuse.codePoint; + utf8Upto += reuse.numBytes; } return utf32Count; } + /** + * Computes the codepoint and codepoint length (in bytes) of the specified {@code offset} in the + * provided {@code utf8} byte array, assuming UTF8 encoding. As with other related methods in this + * class, this assumes valid UTF8 input and does not perform full UTF8 + * validation. Passing invalid UTF8 or a position that is not a valid header byte position may + * result in undefined behavior. This makes no attempt to synchronize or validate. + */ + public static UTF8CodePoint codePointAt(byte[] utf8, int pos, UTF8CodePoint reuse) { + if (reuse == null) { + reuse = new UTF8CodePoint(); + } + + int leadByte = utf8[pos] & 0xFF; + int numBytes = utf8CodeLength[leadByte]; + reuse.numBytes = numBytes; + int v; + switch (numBytes) { + case 1: + reuse.codePoint = leadByte; + return reuse; + case 2: + v = leadByte & 31; // 5 useful bits + break; + case 3: + v = leadByte & 15; // 4 useful bits + break; + case 4: + v = leadByte & 7; // 3 useful bits + break; + default: + throw new IllegalArgumentException( + "Invalid UTF8 header byte: 0x" + Integer.toHexString(leadByte)); + } + + // TODO: this may read past utf8's limit. + final int limit = pos + numBytes; + pos++; + while (pos < limit) { + v = v << 6 | utf8[pos++] & 63; + } + reuse.codePoint = v; + + return reuse; + } + + /** Holds a codepoint along with the number of bytes required to represent it in UTF8 */ + public static final class UTF8CodePoint { + public int codePoint; + public int numBytes; + } + /** Shift value for lead surrogate to form a supplementary character. */ private static final int LEAD_SURROGATE_SHIFT_ = 10; /** Mask to retrieve the significant value from a trail surrogate. */ diff --git a/lucene/core/src/java/org/apache/lucene/util/VectorUtil.java b/lucene/core/src/java/org/apache/lucene/util/VectorUtil.java index 2a08436ec0b0..0921bb75a664 100644 --- a/lucene/core/src/java/org/apache/lucene/util/VectorUtil.java +++ b/lucene/core/src/java/org/apache/lucene/util/VectorUtil.java @@ -20,6 +20,8 @@ /** Utilities for computations with numeric arrays */ public final class VectorUtil { + private static final VectorUtilProvider PROVIDER = VectorUtilProvider.lookup(false); + private VectorUtil() {} /** @@ -31,68 +33,9 @@ public static float dotProduct(float[] a, float[] b) { if (a.length != b.length) { throw new IllegalArgumentException("vector dimensions differ: " + a.length + "!=" + b.length); } - float res = 0f; - /* - * If length of vector is larger than 8, we use unrolled dot product to accelerate the - * calculation. - */ - int i; - for (i = 0; i < a.length % 8; i++) { - res += b[i] * a[i]; - } - if (a.length < 8) { - return res; - } - for (; i + 31 < a.length; i += 32) { - res += - b[i + 0] * a[i + 0] - + b[i + 1] * a[i + 1] - + b[i + 2] * a[i + 2] - + b[i + 3] * a[i + 3] - + b[i + 4] * a[i + 4] - + b[i + 5] * a[i + 5] - + b[i + 6] * a[i + 6] - + b[i + 7] * a[i + 7]; - res += - b[i + 8] * a[i + 8] - + b[i + 9] * a[i + 9] - + b[i + 10] * a[i + 10] - + b[i + 11] * a[i + 11] - + b[i + 12] * a[i + 12] - + b[i + 13] * a[i + 13] - + b[i + 14] * a[i + 14] - + b[i + 15] * a[i + 15]; - res += - b[i + 16] * a[i + 16] - + b[i + 17] * a[i + 17] - + b[i + 18] * a[i + 18] - + b[i + 19] * a[i + 19] - + b[i + 20] * a[i + 20] - + b[i + 21] * a[i + 21] - + b[i + 22] * a[i + 22] - + b[i + 23] * a[i + 23]; - res += - b[i + 24] * a[i + 24] - + b[i + 25] * a[i + 25] - + b[i + 26] * a[i + 26] - + b[i + 27] * a[i + 27] - + b[i + 28] * a[i + 28] - + b[i + 29] * a[i + 29] - + b[i + 30] * a[i + 30] - + b[i + 31] * a[i + 31]; - } - for (; i + 7 < a.length; i += 8) { - res += - b[i + 0] * a[i + 0] - + b[i + 1] * a[i + 1] - + b[i + 2] * a[i + 2] - + b[i + 3] * a[i + 3] - + b[i + 4] * a[i + 4] - + b[i + 5] * a[i + 5] - + b[i + 6] * a[i + 6] - + b[i + 7] * a[i + 7]; - } - return res; + float r = PROVIDER.dotProduct(a, b); + assert Float.isFinite(r); + return r; } /** @@ -100,42 +43,21 @@ public static float dotProduct(float[] a, float[] b) { * * @throws IllegalArgumentException if the vectors' dimensions differ. */ - public static float cosine(float[] v1, float[] v2) { - if (v1.length != v2.length) { - throw new IllegalArgumentException( - "vector dimensions differ: " + v1.length + "!=" + v2.length); - } - - float sum = 0.0f; - float norm1 = 0.0f; - float norm2 = 0.0f; - int dim = v1.length; - - for (int i = 0; i < dim; i++) { - float elem1 = v1[i]; - float elem2 = v2[i]; - sum += elem1 * elem2; - norm1 += elem1 * elem1; - norm2 += elem2 * elem2; + public static float cosine(float[] a, float[] b) { + if (a.length != b.length) { + throw new IllegalArgumentException("vector dimensions differ: " + a.length + "!=" + b.length); } - return (float) (sum / Math.sqrt(norm1 * norm2)); + float r = PROVIDER.cosine(a, b); + assert Float.isFinite(r); + return r; } /** Returns the cosine similarity between the two vectors. */ public static float cosine(byte[] a, byte[] b) { - // Note: this will not overflow if dim < 2^18, since max(byte * byte) = 2^14. - int sum = 0; - int norm1 = 0; - int norm2 = 0; - - for (int i = 0; i < a.length; i++) { - byte elem1 = a[i]; - byte elem2 = b[i]; - sum += elem1 * elem2; - norm1 += elem1 * elem1; - norm2 += elem2 * elem2; + if (a.length != b.length) { + throw new IllegalArgumentException("vector dimensions differ: " + a.length + "!=" + b.length); } - return (float) (sum / Math.sqrt((double) norm1 * (double) norm2)); + return PROVIDER.cosine(a, b); } /** @@ -143,52 +65,21 @@ public static float cosine(byte[] a, byte[] b) { * * @throws IllegalArgumentException if the vectors' dimensions differ. */ - public static float squareDistance(float[] v1, float[] v2) { - if (v1.length != v2.length) { - throw new IllegalArgumentException( - "vector dimensions differ: " + v1.length + "!=" + v2.length); - } - float squareSum = 0.0f; - int dim = v1.length; - int i; - for (i = 0; i + 8 <= dim; i += 8) { - squareSum += squareDistanceUnrolled(v1, v2, i); - } - for (; i < dim; i++) { - float diff = v1[i] - v2[i]; - squareSum += diff * diff; + public static float squareDistance(float[] a, float[] b) { + if (a.length != b.length) { + throw new IllegalArgumentException("vector dimensions differ: " + a.length + "!=" + b.length); } - return squareSum; - } - - private static float squareDistanceUnrolled(float[] v1, float[] v2, int index) { - float diff0 = v1[index + 0] - v2[index + 0]; - float diff1 = v1[index + 1] - v2[index + 1]; - float diff2 = v1[index + 2] - v2[index + 2]; - float diff3 = v1[index + 3] - v2[index + 3]; - float diff4 = v1[index + 4] - v2[index + 4]; - float diff5 = v1[index + 5] - v2[index + 5]; - float diff6 = v1[index + 6] - v2[index + 6]; - float diff7 = v1[index + 7] - v2[index + 7]; - return diff0 * diff0 - + diff1 * diff1 - + diff2 * diff2 - + diff3 * diff3 - + diff4 * diff4 - + diff5 * diff5 - + diff6 * diff6 - + diff7 * diff7; + float r = PROVIDER.squareDistance(a, b); + assert Float.isFinite(r); + return r; } /** Returns the sum of squared differences of the two vectors. */ public static int squareDistance(byte[] a, byte[] b) { - // Note: this will not overflow if dim < 2^18, since max(byte * byte) = 2^14. - int squareSum = 0; - for (int i = 0; i < a.length; i++) { - int diff = a[i] - b[i]; - squareSum += diff * diff; + if (a.length != b.length) { + throw new IllegalArgumentException("vector dimensions differ: " + a.length + "!=" + b.length); } - return squareSum; + return PROVIDER.squareDistance(a, b); } /** @@ -250,12 +141,10 @@ public static void add(float[] u, float[] v) { * @return the value of the dot product of the two vectors */ public static int dotProduct(byte[] a, byte[] b) { - assert a.length == b.length; - int total = 0; - for (int i = 0; i < a.length; i++) { - total += a[i] * b[i]; + if (a.length != b.length) { + throw new IllegalArgumentException("vector dimensions differ: " + a.length + "!=" + b.length); } - return total; + return PROVIDER.dotProduct(a, b); } /** @@ -270,4 +159,20 @@ public static float dotProductScore(byte[] a, byte[] b) { float denom = (float) (a.length * (1 << 15)); return 0.5f + dotProduct(a, b) / denom; } + + /** + * Checks if a float vector only has finite components. + * + * @param v bytes containing a vector + * @return the vector for call-chaining + * @throws IllegalArgumentException if any component of vector is not finite + */ + public static float[] checkFinite(float[] v) { + for (int i = 0; i < v.length; i++) { + if (!Float.isFinite(v[i])) { + throw new IllegalArgumentException("non-finite value at vector[" + i + "]=" + v[i]); + } + } + return v; + } } diff --git a/lucene/core/src/java/org/apache/lucene/util/VectorUtilDefaultProvider.java b/lucene/core/src/java/org/apache/lucene/util/VectorUtilDefaultProvider.java new file mode 100644 index 000000000000..665181e86788 --- /dev/null +++ b/lucene/core/src/java/org/apache/lucene/util/VectorUtilDefaultProvider.java @@ -0,0 +1,178 @@ +/* + * 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.util; + +/** The default VectorUtil provider implementation. */ +final class VectorUtilDefaultProvider implements VectorUtilProvider { + + VectorUtilDefaultProvider() {} + + @Override + public float dotProduct(float[] a, float[] b) { + float res = 0f; + /* + * If length of vector is larger than 8, we use unrolled dot product to accelerate the + * calculation. + */ + int i; + for (i = 0; i < a.length % 8; i++) { + res += b[i] * a[i]; + } + if (a.length < 8) { + return res; + } + for (; i + 31 < a.length; i += 32) { + res += + b[i + 0] * a[i + 0] + + b[i + 1] * a[i + 1] + + b[i + 2] * a[i + 2] + + b[i + 3] * a[i + 3] + + b[i + 4] * a[i + 4] + + b[i + 5] * a[i + 5] + + b[i + 6] * a[i + 6] + + b[i + 7] * a[i + 7]; + res += + b[i + 8] * a[i + 8] + + b[i + 9] * a[i + 9] + + b[i + 10] * a[i + 10] + + b[i + 11] * a[i + 11] + + b[i + 12] * a[i + 12] + + b[i + 13] * a[i + 13] + + b[i + 14] * a[i + 14] + + b[i + 15] * a[i + 15]; + res += + b[i + 16] * a[i + 16] + + b[i + 17] * a[i + 17] + + b[i + 18] * a[i + 18] + + b[i + 19] * a[i + 19] + + b[i + 20] * a[i + 20] + + b[i + 21] * a[i + 21] + + b[i + 22] * a[i + 22] + + b[i + 23] * a[i + 23]; + res += + b[i + 24] * a[i + 24] + + b[i + 25] * a[i + 25] + + b[i + 26] * a[i + 26] + + b[i + 27] * a[i + 27] + + b[i + 28] * a[i + 28] + + b[i + 29] * a[i + 29] + + b[i + 30] * a[i + 30] + + b[i + 31] * a[i + 31]; + } + for (; i + 7 < a.length; i += 8) { + res += + b[i + 0] * a[i + 0] + + b[i + 1] * a[i + 1] + + b[i + 2] * a[i + 2] + + b[i + 3] * a[i + 3] + + b[i + 4] * a[i + 4] + + b[i + 5] * a[i + 5] + + b[i + 6] * a[i + 6] + + b[i + 7] * a[i + 7]; + } + return res; + } + + @Override + public float cosine(float[] a, float[] b) { + float sum = 0.0f; + float norm1 = 0.0f; + float norm2 = 0.0f; + int dim = a.length; + + for (int i = 0; i < dim; i++) { + float elem1 = a[i]; + float elem2 = b[i]; + sum += elem1 * elem2; + norm1 += elem1 * elem1; + norm2 += elem2 * elem2; + } + return (float) (sum / Math.sqrt((double) norm1 * (double) norm2)); + } + + @Override + public float squareDistance(float[] a, float[] b) { + float squareSum = 0.0f; + int dim = a.length; + int i; + for (i = 0; i + 8 <= dim; i += 8) { + squareSum += squareDistanceUnrolled(a, b, i); + } + for (; i < dim; i++) { + float diff = a[i] - b[i]; + squareSum += diff * diff; + } + return squareSum; + } + + private static float squareDistanceUnrolled(float[] v1, float[] v2, int index) { + float diff0 = v1[index + 0] - v2[index + 0]; + float diff1 = v1[index + 1] - v2[index + 1]; + float diff2 = v1[index + 2] - v2[index + 2]; + float diff3 = v1[index + 3] - v2[index + 3]; + float diff4 = v1[index + 4] - v2[index + 4]; + float diff5 = v1[index + 5] - v2[index + 5]; + float diff6 = v1[index + 6] - v2[index + 6]; + float diff7 = v1[index + 7] - v2[index + 7]; + return diff0 * diff0 + + diff1 * diff1 + + diff2 * diff2 + + diff3 * diff3 + + diff4 * diff4 + + diff5 * diff5 + + diff6 * diff6 + + diff7 * diff7; + } + + @Override + public int dotProduct(byte[] a, byte[] b) { + int total = 0; + for (int i = 0; i < a.length; i++) { + total += a[i] * b[i]; + } + return total; + } + + @Override + public float cosine(byte[] a, byte[] b) { + // Note: this will not overflow if dim < 2^18, since max(byte * byte) = 2^14. + int sum = 0; + int norm1 = 0; + int norm2 = 0; + + for (int i = 0; i < a.length; i++) { + byte elem1 = a[i]; + byte elem2 = b[i]; + sum += elem1 * elem2; + norm1 += elem1 * elem1; + norm2 += elem2 * elem2; + } + return (float) (sum / Math.sqrt((double) norm1 * (double) norm2)); + } + + @Override + public int squareDistance(byte[] a, byte[] b) { + // Note: this will not overflow if dim < 2^18, since max(byte * byte) = 2^14. + int squareSum = 0; + for (int i = 0; i < a.length; i++) { + int diff = a[i] - b[i]; + squareSum += diff * diff; + } + return squareSum; + } +} diff --git a/lucene/core/src/java/org/apache/lucene/util/VectorUtilProvider.java b/lucene/core/src/java/org/apache/lucene/util/VectorUtilProvider.java new file mode 100644 index 000000000000..3fd29c2bf349 --- /dev/null +++ b/lucene/core/src/java/org/apache/lucene/util/VectorUtilProvider.java @@ -0,0 +1,146 @@ +/* + * 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.util; + +import java.lang.Runtime.Version; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Locale; +import java.util.Objects; +import java.util.logging.Logger; + +/** A provider of VectorUtil implementations. */ +interface VectorUtilProvider { + + /** Calculates the dot product of the given float arrays. */ + float dotProduct(float[] a, float[] b); + + /** Returns the cosine similarity between the two vectors. */ + float cosine(float[] v1, float[] v2); + + /** Returns the sum of squared differences of the two vectors. */ + float squareDistance(float[] a, float[] b); + + /** Returns the dot product computed over signed bytes. */ + int dotProduct(byte[] a, byte[] b); + + /** Returns the cosine similarity between the two byte vectors. */ + float cosine(byte[] a, byte[] b); + + /** Returns the sum of squared differences of the two byte vectors. */ + int squareDistance(byte[] a, byte[] b); + + // -- provider lookup mechanism + + static final Logger LOG = Logger.getLogger(VectorUtilProvider.class.getName()); + + /** The minimal version of Java that has the bugfix for JDK-8301190. */ + static final Version VERSION_JDK8301190_FIXED = Version.parse("20.0.2"); + + static VectorUtilProvider lookup(boolean testMode) { + final int runtimeVersion = Runtime.version().feature(); + if (runtimeVersion >= 20 && runtimeVersion <= 21) { + // is locale sane (only buggy in Java 20) + if (isAffectedByJDK8301190()) { + LOG.warning( + "Java runtime is using a buggy default locale; Java vector incubator API can't be enabled: " + + Locale.getDefault()); + return new VectorUtilDefaultProvider(); + } + // is the incubator module present and readable (JVM providers may to exclude them or it is + // build with jlink) + if (!vectorModulePresentAndReadable()) { + LOG.warning( + "Java vector incubator module is not readable. For optimal vector performance, pass '--add-modules jdk.incubator.vector' to enable Vector API."); + return new VectorUtilDefaultProvider(); + } + if (!testMode && isClientVM()) { + LOG.warning("C2 compiler is disabled; Java vector incubator API can't be enabled"); + return new VectorUtilDefaultProvider(); + } + try { + // we use method handles with lookup, so we do not need to deal with setAccessible as we + // have private access through the lookup: + final var lookup = MethodHandles.lookup(); + final var cls = lookup.findClass("org.apache.lucene.util.VectorUtilPanamaProvider"); + final var constr = + lookup.findConstructor(cls, MethodType.methodType(void.class, boolean.class)); + try { + return (VectorUtilProvider) constr.invoke(testMode); + } catch (UnsupportedOperationException uoe) { + // not supported because preferred vector size too small or similar + LOG.warning("Java vector incubator API was not enabled. " + uoe.getMessage()); + return new VectorUtilDefaultProvider(); + } catch (RuntimeException | Error e) { + throw e; + } catch (Throwable th) { + throw new AssertionError(th); + } + } catch (NoSuchMethodException | IllegalAccessException e) { + throw new LinkageError( + "VectorUtilPanamaProvider is missing correctly typed constructor", e); + } catch (ClassNotFoundException cnfe) { + throw new LinkageError("VectorUtilPanamaProvider is missing in Lucene JAR file", cnfe); + } + } else if (runtimeVersion >= 22) { + LOG.warning( + "You are running with Java 22 or later. To make full use of the Vector API, please update Apache Lucene."); + } + return new VectorUtilDefaultProvider(); + } + + private static boolean vectorModulePresentAndReadable() { + var opt = + ModuleLayer.boot().modules().stream() + .filter(m -> m.getName().equals("jdk.incubator.vector")) + .findFirst(); + if (opt.isPresent()) { + VectorUtilProvider.class.getModule().addReads(opt.get()); + return true; + } + return false; + } + + /** + * Check if runtime is affected by JDK-8301190 (avoids assertion when default language is say + * "tr"). + */ + private static boolean isAffectedByJDK8301190() { + return VERSION_JDK8301190_FIXED.compareToIgnoreOptional(Runtime.version()) > 0 + && !Objects.equals("I", "i".toUpperCase(Locale.getDefault())); + } + + @SuppressWarnings("removal") + @SuppressForbidden(reason = "security manager") + private static boolean isClientVM() { + try { + final PrivilegedAction action = + () -> System.getProperty("java.vm.info", "").contains("emulated-client"); + return AccessController.doPrivileged(action); + } catch ( + @SuppressWarnings("unused") + SecurityException e) { + LOG.warning( + "SecurityManager denies permission to 'java.vm.info' system property, so state of C2 compiler can't be detected. " + + "In case of performance issues allow access to this property."); + return false; + } + } +} diff --git a/lucene/core/src/java/org/apache/lucene/util/Version.java b/lucene/core/src/java/org/apache/lucene/util/Version.java index 3bc4be34d5a1..bd37efbd8187 100644 --- a/lucene/core/src/java/org/apache/lucene/util/Version.java +++ b/lucene/core/src/java/org/apache/lucene/util/Version.java @@ -259,11 +259,16 @@ public final class Version { @Deprecated public static final Version LUCENE_9_5_0 = new Version(9, 5, 0); /** - * Match settings and bugs in Lucene's 9.6.0 release. + * @deprecated (9.7.0) Use latest + */ + @Deprecated public static final Version LUCENE_9_6_0 = new Version(9, 6, 0); + + /** + * Match settings and bugs in Lucene's 9.7.0 release. * *

    Use this to get the latest & greatest settings, bug fixes, etc, for Lucene. */ - public static final Version LUCENE_9_6_0 = new Version(9, 6, 0); + public static final Version LUCENE_9_7_0 = new Version(9, 7, 0); // To add a new version: // * Only add above this comment @@ -279,7 +284,7 @@ public final class Version { * re-test your entire application to ensure it behaves as expected, as some defaults may * have changed and may break functionality in your application. */ - public static final Version LATEST = LUCENE_9_6_0; + public static final Version LATEST = LUCENE_9_7_0; /** * Constant for backwards compatibility. diff --git a/lucene/core/src/java/org/apache/lucene/util/VirtualMethod.java b/lucene/core/src/java/org/apache/lucene/util/VirtualMethod.java index 05eef2a86617..a7c2a71cc1c8 100644 --- a/lucene/core/src/java/org/apache/lucene/util/VirtualMethod.java +++ b/lucene/core/src/java/org/apache/lucene/util/VirtualMethod.java @@ -17,6 +17,8 @@ package org.apache.lucene.util; import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -49,13 +51,20 @@ * *

      *  final boolean isDeprecatedMethodOverridden =
    - *   oldMethod.getImplementationDistance(this.getClass()) > newMethod.getImplementationDistance(this.getClass());
    + *   AccessController.doPrivileged((PrivilegedAction<Boolean>) () ->
    + *    (oldMethod.getImplementationDistance(this.getClass()) > newMethod.getImplementationDistance(this.getClass())));
      *
      *  // alternatively (more readable):
      *  final boolean isDeprecatedMethodOverridden =
    - *   VirtualMethod.compareImplementationDistance(this.getClass(), oldMethod, newMethod) > 0
    + *   AccessController.doPrivileged((PrivilegedAction<Boolean>) () ->
    + *    VirtualMethod.compareImplementationDistance(this.getClass(), oldMethod, newMethod) > 0);
      * 
    * + *

    It is important to use {@link AccessController#doPrivileged(PrivilegedAction)} for the actual + * call to get the implementation distance because the subclass may be in a different package. The + * static constructors do not need to use {@code AccessController} because it just initializes our + * own method reference. The caller should have access to all declared members in its own class. + * *

    {@link #getImplementationDistance} returns the distance of the subclass that overrides this * method. The one with the larger distance should be used preferable. This way also more * complicated method rename scenarios can be handled (think of 2.9 {@code TokenStream} diff --git a/lucene/core/src/java/org/apache/lucene/util/automaton/Automata.java b/lucene/core/src/java/org/apache/lucene/util/automaton/Automata.java index 9a642338f09b..c829429d3c9b 100644 --- a/lucene/core/src/java/org/apache/lucene/util/automaton/Automata.java +++ b/lucene/core/src/java/org/apache/lucene/util/automaton/Automata.java @@ -29,9 +29,11 @@ package org.apache.lucene.util.automaton; +import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import org.apache.lucene.util.BytesRef; +import org.apache.lucene.util.BytesRefIterator; import org.apache.lucene.util.StringHelper; /** @@ -40,6 +42,11 @@ * @lucene.experimental */ public final class Automata { + /** + * {@link #makeStringUnion(Collection)} limits terms of this max length to ensure the stack + * doesn't overflow while building, since our algorithm currently relies on recursion. + */ + public static final int MAX_STRING_UNION_TERM_LENGTH = 1000; private Automata() {} @@ -573,7 +580,49 @@ public static Automaton makeStringUnion(Collection utf8Strings) { if (utf8Strings.isEmpty()) { return makeEmpty(); } else { - return DaciukMihovAutomatonBuilder.build(utf8Strings); + return DaciukMihovAutomatonBuilder.build(utf8Strings, false); + } + } + + /** + * Returns a new (deterministic and minimal) automaton that accepts the union of the given + * collection of {@link BytesRef}s representing UTF-8 encoded strings. The resulting automaton + * will be built in a binary representation. + * + * @param utf8Strings The input strings, UTF-8 encoded. The collection must be in sorted order. + * @return An {@link Automaton} accepting all input strings. The resulting automaton is binary + * based (UTF-8 encoded byte transition labels). + */ + public static Automaton makeBinaryStringUnion(Collection utf8Strings) { + if (utf8Strings.isEmpty()) { + return makeEmpty(); + } else { + return DaciukMihovAutomatonBuilder.build(utf8Strings, true); } } + + /** + * Returns a new (deterministic and minimal) automaton that accepts the union of the given + * iterator of {@link BytesRef}s representing UTF-8 encoded strings. + * + * @param utf8Strings The input strings, UTF-8 encoded. The iterator must be in sorted order. + * @return An {@link Automaton} accepting all input strings. The resulting automaton is codepoint + * based (full unicode codepoints on transitions). + */ + public static Automaton makeStringUnion(BytesRefIterator utf8Strings) throws IOException { + return DaciukMihovAutomatonBuilder.build(utf8Strings, false); + } + + /** + * Returns a new (deterministic and minimal) automaton that accepts the union of the given + * iterator of {@link BytesRef}s representing UTF-8 encoded strings. The resulting automaton will + * be built in a binary representation. + * + * @param utf8Strings The input strings, UTF-8 encoded. The iterator must be in sorted order. + * @return An {@link Automaton} accepting all input strings. The resulting automaton is binary + * based (UTF-8 encoded byte transition labels). + */ + public static Automaton makeBinaryStringUnion(BytesRefIterator utf8Strings) throws IOException { + return DaciukMihovAutomatonBuilder.build(utf8Strings, true); + } } diff --git a/lucene/core/src/java/org/apache/lucene/util/automaton/DaciukMihovAutomatonBuilder.java b/lucene/core/src/java/org/apache/lucene/util/automaton/DaciukMihovAutomatonBuilder.java index 94002b04a40b..7048d4538d15 100644 --- a/lucene/core/src/java/org/apache/lucene/util/automaton/DaciukMihovAutomatonBuilder.java +++ b/lucene/core/src/java/org/apache/lucene/util/automaton/DaciukMihovAutomatonBuilder.java @@ -16,14 +16,15 @@ */ package org.apache.lucene.util.automaton; +import java.io.IOException; import java.util.Arrays; import java.util.Collection; -import java.util.Comparator; import java.util.HashMap; import java.util.IdentityHashMap; import org.apache.lucene.util.ArrayUtil; import org.apache.lucene.util.BytesRef; -import org.apache.lucene.util.CharsRef; +import org.apache.lucene.util.BytesRefBuilder; +import org.apache.lucene.util.BytesRefIterator; import org.apache.lucene.util.UnicodeUtil; /** @@ -32,14 +33,22 @@ * * @see #build(Collection) * @see Automata#makeStringUnion(Collection) + * @see Automata#makeBinaryStringUnion(Collection) + * @see Automata#makeStringUnion(BytesRefIterator) + * @see Automata#makeBinaryStringUnion(BytesRefIterator) + * @deprecated Visibility of this class will be reduced in a future release. Users can access this + * functionality directly through {@link Automata#makeStringUnion(Collection)} */ +@Deprecated public final class DaciukMihovAutomatonBuilder { /** * This builder rejects terms that are more than 1k chars long since it then uses recursion based * on the length of the string, which might cause stack overflows. + * + * @deprecated See {@link Automata#MAX_STRING_UNION_TERM_LENGTH} */ - public static final int MAX_TERM_LENGTH = 1_000; + @Deprecated public static final int MAX_TERM_LENGTH = 1_000; /** The default constructor is private. Use static methods directly. */ private DaciukMihovAutomatonBuilder() { @@ -179,56 +188,18 @@ private static boolean referenceEquals(Object[] a1, Object[] a2) { private HashMap stateRegistry = new HashMap<>(); /** Root automaton state. */ - private State root = new State(); - - /** Previous sequence added to the automaton in {@link #add(CharsRef)}. */ - private CharsRef previous; + private final State root = new State(); - /** A comparator used for enforcing sorted UTF8 order, used in assertions only. */ - @SuppressWarnings("deprecation") - private static final Comparator comparator = CharsRef.getUTF16SortedAsUTF8Comparator(); + /** Used for input order checking (only through assertions right now) */ + private BytesRefBuilder previous; - /** - * Add another character sequence to this automaton. The sequence must be lexicographically larger - * or equal compared to any previous sequences added to this automaton (the input must be sorted). - */ - public void add(CharsRef current) { - if (current.length > MAX_TERM_LENGTH) { - throw new IllegalArgumentException( - "This builder doesn't allow terms that are larger than 1,000 characters, got " + current); - } - assert stateRegistry != null : "Automaton already built."; - assert previous == null || comparator.compare(previous, current) <= 0 - : "Input must be in sorted UTF-8 order: " + previous + " >= " + current; - assert setPrevious(current); - - // Descend in the automaton (find matching prefix). - int pos = 0, max = current.length(); - State next, state = root; - while (pos < max && (next = state.lastChild(Character.codePointAt(current, pos))) != null) { - state = next; - // todo, optimize me - pos += Character.charCount(Character.codePointAt(current, pos)); + /** Copy current into an internal buffer. */ + private boolean setPrevious(BytesRef current) { + if (previous == null) { + previous = new BytesRefBuilder(); } - - if (state.hasChildren()) replaceOrRegister(state); - - addSuffix(state, current, pos); - } - - /** - * Finalize the automaton and return the root state. No more strings can be added to the builder - * after this call. - * - * @return Root automaton state. - */ - public State complete() { - if (this.stateRegistry == null) throw new IllegalStateException(); - - if (root.hasChildren()) replaceOrRegister(root); - - stateRegistry = null; - return root; + previous.copyBytes(current); + return true; } /** Internal recursive traversal for conversion. */ @@ -253,35 +224,116 @@ private static int convert( return converted; } + /** + * Called after adding all terms. Performs final minimization and converts to a standard {@link + * Automaton} instance. + */ + private Automaton completeAndConvert() { + // Final minimization: + if (this.stateRegistry == null) throw new IllegalStateException(); + if (root.hasChildren()) replaceOrRegister(root); + stateRegistry = null; + + // Convert: + Automaton.Builder a = new Automaton.Builder(); + convert(a, root, new IdentityHashMap<>()); + return a.finish(); + } + /** * Build a minimal, deterministic automaton from a sorted list of {@link BytesRef} representing * strings in UTF-8. These strings must be binary-sorted. + * + * @deprecated Please see {@link Automata#makeStringUnion(Collection)} instead */ + @Deprecated public static Automaton build(Collection input) { + return build(input, false); + } + + /** + * Build a minimal, deterministic automaton from a sorted list of {@link BytesRef} representing + * strings in UTF-8. These strings must be binary-sorted. + */ + static Automaton build(Collection input, boolean asBinary) { final DaciukMihovAutomatonBuilder builder = new DaciukMihovAutomatonBuilder(); - char[] chars = new char[0]; - CharsRef ref = new CharsRef(); for (BytesRef b : input) { - chars = ArrayUtil.grow(chars, b.length); - final int len = UnicodeUtil.UTF8toUTF16(b, chars); - ref.chars = chars; - ref.length = len; - builder.add(ref); + builder.add(b, asBinary); } - Automaton.Builder a = new Automaton.Builder(); - convert(a, builder.complete(), new IdentityHashMap()); + return builder.completeAndConvert(); + } - return a.finish(); + /** + * Build a minimal, deterministic automaton from a sorted list of {@link BytesRef} representing + * strings in UTF-8. These strings must be binary-sorted. Creates an {@link Automaton} with either + * UTF-8 codepoints as transition labels or binary (compiled) transition labels based on {@code + * asBinary}. + */ + static Automaton build(BytesRefIterator input, boolean asBinary) throws IOException { + final DaciukMihovAutomatonBuilder builder = new DaciukMihovAutomatonBuilder(); + + for (BytesRef b = input.next(); b != null; b = input.next()) { + builder.add(b, asBinary); + } + + return builder.completeAndConvert(); } - /** Copy current into an internal buffer. */ - private boolean setPrevious(CharsRef current) { - // don't need to copy, once we fix https://issues.apache.org/jira/browse/LUCENE-3277 - // still, called only from assert - previous = CharsRef.deepCopyOf(current); - return true; + private void add(BytesRef current, boolean asBinary) { + if (current.length > Automata.MAX_STRING_UNION_TERM_LENGTH) { + throw new IllegalArgumentException( + "This builder doesn't allow terms that are larger than " + + Automata.MAX_STRING_UNION_TERM_LENGTH + + " characters, got " + + current); + } + assert stateRegistry != null : "Automaton already built."; + assert previous == null || previous.get().compareTo(current) <= 0 + : "Input must be in sorted UTF-8 order: " + previous.get() + " >= " + current; + assert setPrevious(current); + + // Reusable codepoint information if we're building a non-binary based automaton + UnicodeUtil.UTF8CodePoint codePoint = null; + + // Descend in the automaton (find matching prefix). + byte[] bytes = current.bytes; + int pos = current.offset, max = current.offset + current.length; + State next, state = root; + if (asBinary) { + while (pos < max && (next = state.lastChild(bytes[pos] & 0xff)) != null) { + state = next; + pos++; + } + } else { + while (pos < max) { + codePoint = UnicodeUtil.codePointAt(bytes, pos, codePoint); + next = state.lastChild(codePoint.codePoint); + if (next == null) { + break; + } + state = next; + pos += codePoint.numBytes; + } + } + + if (state.hasChildren()) replaceOrRegister(state); + + // Add suffix + if (asBinary) { + while (pos < max) { + state = state.newState(bytes[pos] & 0xff); + pos++; + } + } else { + while (pos < max) { + codePoint = UnicodeUtil.codePointAt(bytes, pos, codePoint); + state = state.newState(codePoint.codePoint); + pos += codePoint.numBytes; + } + } + state.is_final = true; } /** @@ -300,18 +352,4 @@ private void replaceOrRegister(State state) { stateRegistry.put(child, child); } } - - /** - * Add a suffix of current starting at fromIndex (inclusive) to state - * state. - */ - private void addSuffix(State state, CharSequence current, int fromIndex) { - final int len = current.length(); - while (fromIndex < len) { - int cp = Character.codePointAt(current, fromIndex); - state = state.newState(cp); - fromIndex += Character.charCount(cp); - } - state.is_final = true; - } } diff --git a/lucene/core/src/java/org/apache/lucene/util/automaton/Operations.java b/lucene/core/src/java/org/apache/lucene/util/automaton/Operations.java index 6db58e7119ea..9ebe5b998037 100644 --- a/lucene/core/src/java/org/apache/lucene/util/automaton/Operations.java +++ b/lucene/core/src/java/org/apache/lucene/util/automaton/Operations.java @@ -1135,7 +1135,7 @@ public static String getCommonPrefix(Automaton a) { FixedBitSet tmp = current; current = next; next = tmp; - next.clear(0, next.length()); + next.clear(); } return builder.toString(); } @@ -1311,9 +1311,22 @@ static Automaton totalize(Automaton a) { } /** - * Returns the topological sort of all states reachable from the initial state. Behavior is - * undefined if this automaton has cycles. CPU cost is O(numTransitions), and the implementation - * is recursive so an automaton matching long strings may exhaust the java stack. + * Returns the topological sort of all states reachable from the initial state. This method + * assumes that the automaton does not contain cycles, and will throw an IllegalArgumentException + * if a cycle is detected. The CPU cost is O(numTransitions), and the implementation is + * non-recursive, so it will not exhaust the java stack for automaton matching long strings. If + * there are dead states in the automaton, they will be removed from the returned array. + * + *

    Note: This method uses a deque to iterative the states, which could potentially consume a + * lot of heap space for some automatons. Specifically, automatons with a deep level of states + * (i.e., a large number of transitions from the initial state to the final state) may + * particularly contribute to high memory usage. The memory consumption of this method can be + * considered as O(N), where N is the depth of the automaton (the maximum number of transitions + * from the initial state to any state). However, as this method detects cycles, it will never + * attempt to use infinite RAM. + * + * @param a the Automaton to be sorted + * @return the topologically sorted array of state ids */ public static int[] topoSortStates(Automaton a) { if (a.getNumStates() == 0) { @@ -1321,8 +1334,7 @@ public static int[] topoSortStates(Automaton a) { } int numStates = a.getNumStates(); int[] states = new int[numStates]; - final BitSet visited = new BitSet(numStates); - int upto = topoSortStatesRecurse(a, visited, states, 0, 0, 0); + int upto = topoSortStates(a, states); if (upto < states.length) { // There were dead states @@ -1341,24 +1353,49 @@ public static int[] topoSortStates(Automaton a) { return states; } - // TODO: not great that this is recursive... in theory a - // large automata could exceed java's stack so the maximum level of recursion is bounded to 1000 - private static int topoSortStatesRecurse( - Automaton a, BitSet visited, int[] states, int upto, int state, int level) { - if (level > MAX_RECURSION_LEVEL) { - throw new IllegalArgumentException("input automaton is too large: " + level); - } + /** + * Performs a topological sort on the states of the given Automaton. + * + * @param a The automaton whose states are to be topologically sorted. + * @param states An int array which stores the states. + * @return the number of states in the final sorted list. + * @throws IllegalArgumentException if the input automaton has a cycle. + */ + private static int topoSortStates(Automaton a, int[] states) { + BitSet onStack = new BitSet(a.getNumStates()); + BitSet visited = new BitSet(a.getNumStates()); + var stack = new ArrayDeque(); + stack.push(0); // Assuming that the initial state is 0. + int upto = 0; Transition t = new Transition(); - int count = a.initTransition(state, t); - for (int i = 0; i < count; i++) { - a.getNextTransition(t); - if (!visited.get(t.dest)) { - visited.set(t.dest); - upto = topoSortStatesRecurse(a, visited, states, upto, t.dest, level + 1); + + while (!stack.isEmpty()) { + int state = stack.peek(); // Just peek, don't remove the state yet + + int count = a.initTransition(state, t); + boolean pushed = false; + for (int i = 0; i < count; i++) { + a.getNextTransition(t); + if (!visited.get(t.dest)) { + visited.set(t.dest); + stack.push(t.dest); // Push the next unvisited state onto the stack + onStack.set(state); + pushed = true; + break; // Exit the loop, we'll continue from here in the next iteration + } else if (onStack.get(t.dest)) { + // If the state is on the current recursion stack, we have detected a cycle + throw new IllegalArgumentException("Input automaton has a cycle."); + } + } + + // If we haven't pushed any new state onto the stack, we're done with this state + if (!pushed) { + onStack.clear(state); // remove the node from the current recursion stack + stack.pop(); + states[upto] = state; + upto++; } } - states[upto] = state; - upto++; return upto; } } diff --git a/lucene/core/src/java/org/apache/lucene/util/graph/GraphTokenStreamFiniteStrings.java b/lucene/core/src/java/org/apache/lucene/util/graph/GraphTokenStreamFiniteStrings.java index 6711dfb6230f..321c6ff133a0 100644 --- a/lucene/core/src/java/org/apache/lucene/util/graph/GraphTokenStreamFiniteStrings.java +++ b/lucene/core/src/java/org/apache/lucene/util/graph/GraphTokenStreamFiniteStrings.java @@ -45,6 +45,8 @@ * different paths of the {@link Automaton}. */ public final class GraphTokenStreamFiniteStrings { + /** Maximum level of recursion allowed in recursive operations. */ + private static final int MAX_RECURSION_LEVEL = 1000; private AttributeSource[] tokens = new AttributeSource[4]; private final Automaton det; @@ -271,7 +273,12 @@ private static void articulationPointsRecurse( a.getNextTransition(t); if (visited.get(t.dest) == false) { parent[t.dest] = state; - articulationPointsRecurse(a, t.dest, d + 1, depth, low, parent, visited, points); + if (d < MAX_RECURSION_LEVEL) { + articulationPointsRecurse(a, t.dest, d + 1, depth, low, parent, visited, points); + } else { + throw new IllegalArgumentException( + "Exceeded maximum recursion level during graph analysis"); + } childCount++; if (low[t.dest] >= depth[state]) { isArticulation = true; diff --git a/lucene/core/src/java/org/apache/lucene/util/hnsw/HnswGraphBuilder.java b/lucene/core/src/java/org/apache/lucene/util/hnsw/HnswGraphBuilder.java index 2c5e84be2859..5738cc8c75d8 100644 --- a/lucene/core/src/java/org/apache/lucene/util/hnsw/HnswGraphBuilder.java +++ b/lucene/core/src/java/org/apache/lucene/util/hnsw/HnswGraphBuilder.java @@ -41,8 +41,17 @@ */ public final class HnswGraphBuilder { + /** Default number of maximum connections per node */ + public static final int DEFAULT_MAX_CONN = 16; + + /** + * Default number of the size of the queue maintained while searching during a graph construction. + */ + public static final int DEFAULT_BEAM_WIDTH = 100; + /** Default random seed for level generation * */ private static final long DEFAULT_RAND_SEED = 42; + /** A name for the HNSW component for the info-stream * */ public static final String HNSW_COMPONENT = "HNSW"; @@ -220,7 +229,9 @@ private void initializeFromGraph( binaryValue, (byte[]) vectorsCopy.vectorValue(newNeighbor)); break; } - newNeighbors.insertSorted(newNeighbor, score); + // we are not sure whether the previous graph contains + // unchecked nodes, so we have to assume they're all unchecked + newNeighbors.addOutOfOrder(newNeighbor, score); } } } @@ -316,11 +327,11 @@ private void addDiverseNeighbors(int level, int node, NeighborQueue candidates) int size = neighbors.size(); for (int i = 0; i < size; i++) { int nbr = neighbors.node[i]; - NeighborArray nbrNbr = hnsw.getNeighbors(level, nbr); - nbrNbr.insertSorted(node, neighbors.score[i]); - if (nbrNbr.size() > maxConnOnLevel) { - int indexToRemove = findWorstNonDiverse(nbrNbr); - nbrNbr.removeIndex(indexToRemove); + NeighborArray nbrsOfNbr = hnsw.getNeighbors(level, nbr); + nbrsOfNbr.addOutOfOrder(node, neighbors.score[i]); + if (nbrsOfNbr.size() > maxConnOnLevel) { + int indexToRemove = findWorstNonDiverse(nbrsOfNbr); + nbrsOfNbr.removeIndex(indexToRemove); } } } @@ -335,7 +346,7 @@ private void selectAndLinkDiverse( float cScore = candidates.score[i]; assert cNode < hnsw.size(); if (diversityCheck(cNode, cScore, neighbors)) { - neighbors.add(cNode, cScore); + neighbors.addInOrder(cNode, cScore); } } } @@ -347,7 +358,7 @@ private void popToScratch(NeighborQueue candidates) { // sorted from worst to best for (int i = 0; i < candidateCount; i++) { float maxSimilarity = candidates.topScore(); - scratch.add(candidates.pop(), maxSimilarity); + scratch.addInOrder(candidates.pop(), maxSimilarity); } } @@ -405,53 +416,119 @@ private boolean isDiverse(byte[] candidate, NeighborArray neighbors, float score * neighbours */ private int findWorstNonDiverse(NeighborArray neighbors) throws IOException { + int[] uncheckedIndexes = neighbors.sort(); + if (uncheckedIndexes == null) { + // all nodes are checked, we will directly return the most distant one + return neighbors.size() - 1; + } + int uncheckedCursor = uncheckedIndexes.length - 1; for (int i = neighbors.size() - 1; i > 0; i--) { - if (isWorstNonDiverse(i, neighbors)) { + if (uncheckedCursor < 0) { + // no unchecked node left + break; + } + if (isWorstNonDiverse(i, neighbors, uncheckedIndexes, uncheckedCursor)) { return i; } + if (i == uncheckedIndexes[uncheckedCursor]) { + uncheckedCursor--; + } } return neighbors.size() - 1; } - private boolean isWorstNonDiverse(int candidateIndex, NeighborArray neighbors) + private boolean isWorstNonDiverse( + int candidateIndex, NeighborArray neighbors, int[] uncheckedIndexes, int uncheckedCursor) throws IOException { int candidateNode = neighbors.node[candidateIndex]; switch (vectorEncoding) { case BYTE: return isWorstNonDiverse( - candidateIndex, (byte[]) vectors.vectorValue(candidateNode), neighbors); + candidateIndex, + (byte[]) vectors.vectorValue(candidateNode), + neighbors, + uncheckedIndexes, + uncheckedCursor); default: case FLOAT32: return isWorstNonDiverse( - candidateIndex, (float[]) vectors.vectorValue(candidateNode), neighbors); + candidateIndex, + (float[]) vectors.vectorValue(candidateNode), + neighbors, + uncheckedIndexes, + uncheckedCursor); } } private boolean isWorstNonDiverse( - int candidateIndex, float[] candidateVector, NeighborArray neighbors) throws IOException { + int candidateIndex, + float[] candidateVector, + NeighborArray neighbors, + int[] uncheckedIndexes, + int uncheckedCursor) + throws IOException { float minAcceptedSimilarity = neighbors.score[candidateIndex]; - for (int i = candidateIndex - 1; i >= 0; i--) { - float neighborSimilarity = - similarityFunction.compare( - candidateVector, (float[]) vectorsCopy.vectorValue(neighbors.node[i])); - // candidate node is too similar to node i given its score relative to the base node - if (neighborSimilarity >= minAcceptedSimilarity) { - return true; + if (candidateIndex == uncheckedIndexes[uncheckedCursor]) { + // the candidate itself is unchecked + for (int i = candidateIndex - 1; i >= 0; i--) { + float neighborSimilarity = + similarityFunction.compare( + candidateVector, (float[]) vectorsCopy.vectorValue(neighbors.node[i])); + // candidate node is too similar to node i given its score relative to the base node + if (neighborSimilarity >= minAcceptedSimilarity) { + return true; + } + } + } else { + // else we just need to make sure candidate does not violate diversity with the (newly + // inserted) unchecked nodes + assert candidateIndex > uncheckedIndexes[uncheckedCursor]; + for (int i = uncheckedCursor; i >= 0; i--) { + float neighborSimilarity = + similarityFunction.compare( + candidateVector, + (float[]) vectorsCopy.vectorValue(neighbors.node[uncheckedIndexes[i]])); + // candidate node is too similar to node i given its score relative to the base node + if (neighborSimilarity >= minAcceptedSimilarity) { + return true; + } } } return false; } private boolean isWorstNonDiverse( - int candidateIndex, byte[] candidateVector, NeighborArray neighbors) throws IOException { + int candidateIndex, + byte[] candidateVector, + NeighborArray neighbors, + int[] uncheckedIndexes, + int uncheckedCursor) + throws IOException { float minAcceptedSimilarity = neighbors.score[candidateIndex]; - for (int i = candidateIndex - 1; i >= 0; i--) { - float neighborSimilarity = - similarityFunction.compare( - candidateVector, (byte[]) vectorsCopy.vectorValue(neighbors.node[i])); - // candidate node is too similar to node i given its score relative to the base node - if (neighborSimilarity >= minAcceptedSimilarity) { - return true; + if (candidateIndex == uncheckedIndexes[uncheckedCursor]) { + // the candidate itself is unchecked + for (int i = candidateIndex - 1; i >= 0; i--) { + float neighborSimilarity = + similarityFunction.compare( + candidateVector, (byte[]) vectorsCopy.vectorValue(neighbors.node[i])); + // candidate node is too similar to node i given its score relative to the base node + if (neighborSimilarity >= minAcceptedSimilarity) { + return true; + } + } + } else { + // else we just need to make sure candidate does not violate diversity with the (newly + // inserted) unchecked nodes + assert candidateIndex > uncheckedIndexes[uncheckedCursor]; + for (int i = uncheckedCursor; i >= 0; i--) { + float neighborSimilarity = + similarityFunction.compare( + candidateVector, + (byte[]) vectorsCopy.vectorValue(neighbors.node[uncheckedIndexes[i]])); + // candidate node is too similar to node i given its score relative to the base node + if (neighborSimilarity >= minAcceptedSimilarity) { + return true; + } } } return false; diff --git a/lucene/core/src/java/org/apache/lucene/util/hnsw/HnswGraphSearcher.java b/lucene/core/src/java/org/apache/lucene/util/hnsw/HnswGraphSearcher.java index 4857d5b9d577..5bc718169466 100644 --- a/lucene/core/src/java/org/apache/lucene/util/hnsw/HnswGraphSearcher.java +++ b/lucene/core/src/java/org/apache/lucene/util/hnsw/HnswGraphSearcher.java @@ -100,28 +100,31 @@ public static NeighborQueue search( similarityFunction, new NeighborQueue(topK, true), new SparseFixedBitSet(vectors.size())); - NeighborQueue results; + return search(query, topK, vectors, graph, graphSearcher, acceptOrds, visitedLimit); + } - int initialEp = graph.entryNode(); - if (initialEp == -1) { - return new NeighborQueue(1, true); - } - int[] eps = new int[] {initialEp}; - int numVisited = 0; - for (int level = graph.numLevels() - 1; level >= 1; level--) { - results = graphSearcher.searchLevel(query, 1, level, eps, vectors, graph, null, visitedLimit); - numVisited += results.visitedCount(); - visitedLimit -= results.visitedCount(); - if (results.incomplete()) { - results.setVisitedCount(numVisited); - return results; - } - eps[0] = results.pop(); - } - results = - graphSearcher.searchLevel(query, topK, 0, eps, vectors, graph, acceptOrds, visitedLimit); - results.setVisitedCount(results.visitedCount() + numVisited); - return results; + /** + * Search {@link OnHeapHnswGraph}, this method is thread safe, for parameters please refer to + * {@link #search(float[], int, RandomAccessVectorValues, VectorEncoding, + * VectorSimilarityFunction, HnswGraph, Bits, int)} + */ + public static NeighborQueue search( + float[] query, + int topK, + RandomAccessVectorValues vectors, + VectorEncoding vectorEncoding, + VectorSimilarityFunction similarityFunction, + OnHeapHnswGraph graph, + Bits acceptOrds, + int visitedLimit) + throws IOException { + OnHeapHnswGraphSearcher graphSearcher = + new OnHeapHnswGraphSearcher<>( + vectorEncoding, + similarityFunction, + new NeighborQueue(topK, true), + new SparseFixedBitSet(vectors.size())); + return search(query, topK, vectors, graph, graphSearcher, acceptOrds, visitedLimit); } /** @@ -161,6 +164,46 @@ public static NeighborQueue search( similarityFunction, new NeighborQueue(topK, true), new SparseFixedBitSet(vectors.size())); + return search(query, topK, vectors, graph, graphSearcher, acceptOrds, visitedLimit); + } + + /** + * Search {@link OnHeapHnswGraph}, this method is thread safe, for parameters please refer to + * {@link #search(byte[], int, RandomAccessVectorValues, VectorEncoding, VectorSimilarityFunction, + * HnswGraph, Bits, int)} + */ + public static NeighborQueue search( + byte[] query, + int topK, + RandomAccessVectorValues vectors, + VectorEncoding vectorEncoding, + VectorSimilarityFunction similarityFunction, + OnHeapHnswGraph graph, + Bits acceptOrds, + int visitedLimit) + throws IOException { + OnHeapHnswGraphSearcher graphSearcher = + new OnHeapHnswGraphSearcher<>( + vectorEncoding, + similarityFunction, + new NeighborQueue(topK, true), + new SparseFixedBitSet(vectors.size())); + return search(query, topK, vectors, graph, graphSearcher, acceptOrds, visitedLimit); + } + + private static NeighborQueue search( + T query, + int topK, + RandomAccessVectorValues vectors, + HnswGraph graph, + HnswGraphSearcher graphSearcher, + Bits acceptOrds, + int visitedLimit) + throws IOException { + int initialEp = graph.entryNode(); + if (initialEp == -1) { + return new NeighborQueue(1, true); + } NeighborQueue results; int[] eps = new int[] {graph.entryNode()}; int numVisited = 0; @@ -252,9 +295,9 @@ private NeighborQueue searchLevel( } int topCandidateNode = candidates.pop(); - graph.seek(level, topCandidateNode); + graphSeek(graph, level, topCandidateNode); int friendOrd; - while ((friendOrd = graph.nextNeighbor()) != NO_MORE_DOCS) { + while ((friendOrd = graphNextNeighbor(graph)) != NO_MORE_DOCS) { assert friendOrd < size : "friendOrd=" + friendOrd + "; size=" + size; if (visited.getAndSet(friendOrd)) { continue; @@ -296,6 +339,62 @@ private void prepareScratchState(int capacity) { if (visited.length() < capacity) { visited = FixedBitSet.ensureCapacity((FixedBitSet) visited, capacity); } - visited.clear(0, visited.length()); + visited.clear(); + } + + /** + * Seek a specific node in the given graph. The default implementation will just call {@link + * HnswGraph#seek(int, int)} + * + * @throws IOException when seeking the graph + */ + void graphSeek(HnswGraph graph, int level, int targetNode) throws IOException { + graph.seek(level, targetNode); + } + + /** + * Get the next neighbor from the graph, you must call {@link #graphSeek(HnswGraph, int, int)} + * before calling this method. The default implementation will just call {@link + * HnswGraph#nextNeighbor()} + * + * @return see {@link HnswGraph#nextNeighbor()} + * @throws IOException when advance neighbors + */ + int graphNextNeighbor(HnswGraph graph) throws IOException { + return graph.nextNeighbor(); + } + + /** + * This class allow {@link OnHeapHnswGraph} to be searched in a thread-safe manner. + * + *

    Note the class itself is NOT thread safe, but since each search will create one new graph + * searcher the search method is thread safe. + */ + private static class OnHeapHnswGraphSearcher extends HnswGraphSearcher { + + private NeighborArray cur; + private int upto; + + private OnHeapHnswGraphSearcher( + VectorEncoding vectorEncoding, + VectorSimilarityFunction similarityFunction, + NeighborQueue candidates, + BitSet visited) { + super(vectorEncoding, similarityFunction, candidates, visited); + } + + @Override + void graphSeek(HnswGraph graph, int level, int targetNode) { + cur = ((OnHeapHnswGraph) graph).getNeighbors(level, targetNode); + upto = -1; + } + + @Override + int graphNextNeighbor(HnswGraph graph) { + if (++upto < cur.size()) { + return cur.node[upto]; + } + return NO_MORE_DOCS; + } } } diff --git a/lucene/core/src/java/org/apache/lucene/util/hnsw/NeighborArray.java b/lucene/core/src/java/org/apache/lucene/util/hnsw/NeighborArray.java index ec1b5ec3e897..b44f7da8b8ad 100644 --- a/lucene/core/src/java/org/apache/lucene/util/hnsw/NeighborArray.java +++ b/lucene/core/src/java/org/apache/lucene/util/hnsw/NeighborArray.java @@ -34,6 +34,7 @@ public class NeighborArray { float[] score; int[] node; + private int sortedNodeSize; public NeighborArray(int maxSize, boolean descOrder) { node = new int[maxSize]; @@ -43,9 +44,10 @@ public NeighborArray(int maxSize, boolean descOrder) { /** * Add a new node to the NeighborArray. The new node must be worse than all previously stored - * nodes. + * nodes. This cannot be called after {@link #addOutOfOrder(int, float)} */ - public void add(int newNode, float newScore) { + public void addInOrder(int newNode, float newScore) { + assert size == sortedNodeSize : "cannot call addInOrder after addOutOfOrder"; if (size == node.length) { node = ArrayUtil.grow(node); score = ArrayUtil.growExact(score, node.length); @@ -54,28 +56,80 @@ public void add(int newNode, float newScore) { float previousScore = score[size - 1]; assert ((scoresDescOrder && (previousScore >= newScore)) || (scoresDescOrder == false && (previousScore <= newScore))) - : "Nodes are added in the incorrect order!"; + : "Nodes are added in the incorrect order! Comparing " + + newScore + + " to " + + Arrays.toString(ArrayUtil.copyOfSubArray(score, 0, size)); } node[size] = newNode; score[size] = newScore; ++size; + ++sortedNodeSize; } - /** Add a new node to the NeighborArray into a correct sort position according to its score. */ - public void insertSorted(int newNode, float newScore) { + /** Add node and score but do not insert as sorted */ + public void addOutOfOrder(int newNode, float newScore) { if (size == node.length) { node = ArrayUtil.grow(node); score = ArrayUtil.growExact(score, node.length); } + node[size] = newNode; + score[size] = newScore; + size++; + } + + /** + * Sort the array according to scores, and return the sorted indexes of previous unsorted nodes + * (unchecked nodes) + * + * @return indexes of newly sorted (unchecked) nodes, in ascending order, or null if the array is + * already fully sorted + */ + public int[] sort() { + if (size == sortedNodeSize) { + // all nodes checked and sorted + return null; + } + assert sortedNodeSize < size; + int[] uncheckedIndexes = new int[size - sortedNodeSize]; + int count = 0; + while (sortedNodeSize != size) { + uncheckedIndexes[count] = insertSortedInternal(); // sortedNodeSize is increased inside + for (int i = 0; i < count; i++) { + if (uncheckedIndexes[i] >= uncheckedIndexes[count]) { + // the previous inserted nodes has been shifted + uncheckedIndexes[i]++; + } + } + count++; + } + Arrays.sort(uncheckedIndexes); + return uncheckedIndexes; + } + + /** insert the first unsorted node into its sorted position */ + private int insertSortedInternal() { + assert sortedNodeSize < size : "Call this method only when there's unsorted node"; + int tmpNode = node[sortedNodeSize]; + float tmpScore = score[sortedNodeSize]; int insertionPoint = scoresDescOrder - ? descSortFindRightMostInsertionPoint(newScore) - : ascSortFindRightMostInsertionPoint(newScore); - System.arraycopy(node, insertionPoint, node, insertionPoint + 1, size - insertionPoint); - System.arraycopy(score, insertionPoint, score, insertionPoint + 1, size - insertionPoint); - node[insertionPoint] = newNode; - score[insertionPoint] = newScore; - ++size; + ? descSortFindRightMostInsertionPoint(tmpScore, sortedNodeSize) + : ascSortFindRightMostInsertionPoint(tmpScore, sortedNodeSize); + System.arraycopy( + node, insertionPoint, node, insertionPoint + 1, sortedNodeSize - insertionPoint); + System.arraycopy( + score, insertionPoint, score, insertionPoint + 1, sortedNodeSize - insertionPoint); + node[insertionPoint] = tmpNode; + score[insertionPoint] = tmpScore; + ++sortedNodeSize; + return insertionPoint; + } + + /** This method is for test only. */ + void insertSorted(int newNode, float newScore) { + addOutOfOrder(newNode, newScore); + insertSortedInternal(); } public int size() { @@ -97,15 +151,20 @@ public float[] score() { public void clear() { size = 0; + sortedNodeSize = 0; } public void removeLast() { size--; + sortedNodeSize = Math.min(sortedNodeSize, size); } public void removeIndex(int idx) { System.arraycopy(node, idx + 1, node, idx, size - idx - 1); System.arraycopy(score, idx + 1, score, idx, size - idx - 1); + if (idx < sortedNodeSize) { + sortedNodeSize--; + } size--; } @@ -114,11 +173,11 @@ public String toString() { return "NeighborArray[" + size + "]"; } - private int ascSortFindRightMostInsertionPoint(float newScore) { - int insertionPoint = Arrays.binarySearch(score, 0, size, newScore); + private int ascSortFindRightMostInsertionPoint(float newScore, int bound) { + int insertionPoint = Arrays.binarySearch(score, 0, bound, newScore); if (insertionPoint >= 0) { // find the right most position with the same score - while ((insertionPoint < size - 1) && (score[insertionPoint + 1] == score[insertionPoint])) { + while ((insertionPoint < bound - 1) && (score[insertionPoint + 1] == score[insertionPoint])) { insertionPoint++; } insertionPoint++; @@ -128,9 +187,9 @@ private int ascSortFindRightMostInsertionPoint(float newScore) { return insertionPoint; } - private int descSortFindRightMostInsertionPoint(float newScore) { + private int descSortFindRightMostInsertionPoint(float newScore, int bound) { int start = 0; - int end = size - 1; + int end = bound - 1; while (start <= end) { int mid = (start + end) / 2; if (score[mid] < newScore) end = mid - 1; diff --git a/lucene/core/src/java/org/apache/lucene/util/hnsw/OnHeapHnswGraph.java b/lucene/core/src/java/org/apache/lucene/util/hnsw/OnHeapHnswGraph.java index 9862536de08c..75a77af056a2 100644 --- a/lucene/core/src/java/org/apache/lucene/util/hnsw/OnHeapHnswGraph.java +++ b/lucene/core/src/java/org/apache/lucene/util/hnsw/OnHeapHnswGraph.java @@ -170,14 +170,14 @@ public NodesIterator getNodesOnLevel(int level) { public long ramBytesUsed() { long neighborArrayBytes0 = nsize0 * (Integer.BYTES + Float.BYTES) - + RamUsageEstimator.NUM_BYTES_ARRAY_HEADER * 2 - + RamUsageEstimator.NUM_BYTES_OBJECT_REF - + Integer.BYTES * 2; + + RamUsageEstimator.NUM_BYTES_ARRAY_HEADER + + RamUsageEstimator.NUM_BYTES_OBJECT_REF * 2 + + Integer.BYTES * 3; long neighborArrayBytes = nsize * (Integer.BYTES + Float.BYTES) - + RamUsageEstimator.NUM_BYTES_ARRAY_HEADER * 2 - + RamUsageEstimator.NUM_BYTES_OBJECT_REF - + Integer.BYTES * 2; + + RamUsageEstimator.NUM_BYTES_ARRAY_HEADER + + RamUsageEstimator.NUM_BYTES_OBJECT_REF * 2 + + Integer.BYTES * 3; long total = 0; for (int l = 0; l < numLevels; l++) { if (l == 0) { diff --git a/lucene/core/src/java20/org/apache/lucene/util/VectorUtilPanamaProvider.java b/lucene/core/src/java20/org/apache/lucene/util/VectorUtilPanamaProvider.java new file mode 100644 index 000000000000..a1a5a404223f --- /dev/null +++ b/lucene/core/src/java20/org/apache/lucene/util/VectorUtilPanamaProvider.java @@ -0,0 +1,499 @@ +/* + * 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.util; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.logging.Logger; +import jdk.incubator.vector.ByteVector; +import jdk.incubator.vector.FloatVector; +import jdk.incubator.vector.IntVector; +import jdk.incubator.vector.ShortVector; +import jdk.incubator.vector.Vector; +import jdk.incubator.vector.VectorOperators; +import jdk.incubator.vector.VectorShape; +import jdk.incubator.vector.VectorSpecies; + +/** A VectorUtil provider implementation that leverages the Panama Vector API. */ +final class VectorUtilPanamaProvider implements VectorUtilProvider { + + private static final int INT_SPECIES_PREF_BIT_SIZE = IntVector.SPECIES_PREFERRED.vectorBitSize(); + + private static final VectorSpecies PREF_FLOAT_SPECIES = FloatVector.SPECIES_PREFERRED; + private static final VectorSpecies PREF_BYTE_SPECIES; + private static final VectorSpecies PREF_SHORT_SPECIES; + + /** + * x86 and less than 256-bit vectors. + * + *

    it could be that it has only AVX1 and integer vectors are fast. it could also be that it has + * no AVX and integer vectors are extremely slow. don't use integer vectors to avoid landmines. + */ + private final boolean hasFastIntegerVectors; + + static { + if (INT_SPECIES_PREF_BIT_SIZE >= 256) { + PREF_BYTE_SPECIES = + ByteVector.SPECIES_MAX.withShape( + VectorShape.forBitSize(IntVector.SPECIES_PREFERRED.vectorBitSize() >> 2)); + PREF_SHORT_SPECIES = + ShortVector.SPECIES_MAX.withShape( + VectorShape.forBitSize(IntVector.SPECIES_PREFERRED.vectorBitSize() >> 1)); + } else { + PREF_BYTE_SPECIES = null; + PREF_SHORT_SPECIES = null; + } + } + + // Extracted to a method to be able to apply the SuppressForbidden annotation + @SuppressWarnings("removal") + @SuppressForbidden(reason = "security manager") + private static T doPrivileged(PrivilegedAction action) { + return AccessController.doPrivileged(action); + } + + VectorUtilPanamaProvider(boolean testMode) { + if (!testMode && INT_SPECIES_PREF_BIT_SIZE < 128) { + throw new UnsupportedOperationException( + "Vector bit size is less than 128: " + INT_SPECIES_PREF_BIT_SIZE); + } + + // hack to work around for JDK-8309727: + try { + doPrivileged( + () -> + FloatVector.fromArray(PREF_FLOAT_SPECIES, new float[PREF_FLOAT_SPECIES.length()], 0)); + } catch (SecurityException se) { + throw new UnsupportedOperationException( + "We hit initialization failure described in JDK-8309727: " + se); + } + + // check if the system is x86 and less than 256-bit vectors: + var isAMD64withoutAVX2 = Constants.OS_ARCH.equals("amd64") && INT_SPECIES_PREF_BIT_SIZE < 256; + this.hasFastIntegerVectors = testMode || false == isAMD64withoutAVX2; + + var log = Logger.getLogger(getClass().getName()); + log.info( + "Java vector incubator API enabled" + + (testMode ? " (test mode)" : "") + + "; uses preferredBitSize=" + + INT_SPECIES_PREF_BIT_SIZE); + } + + @Override + public float dotProduct(float[] a, float[] b) { + int i = 0; + float res = 0; + // if the array size is large (> 2x platform vector size), its worth the overhead to vectorize + if (a.length > 2 * PREF_FLOAT_SPECIES.length()) { + // vector loop is unrolled 4x (4 accumulators in parallel) + FloatVector acc1 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector acc2 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector acc3 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector acc4 = FloatVector.zero(PREF_FLOAT_SPECIES); + int upperBound = PREF_FLOAT_SPECIES.loopBound(a.length - 3 * PREF_FLOAT_SPECIES.length()); + for (; i < upperBound; i += 4 * PREF_FLOAT_SPECIES.length()) { + FloatVector va = FloatVector.fromArray(PREF_FLOAT_SPECIES, a, i); + FloatVector vb = FloatVector.fromArray(PREF_FLOAT_SPECIES, b, i); + acc1 = acc1.add(va.mul(vb)); + FloatVector vc = + FloatVector.fromArray(PREF_FLOAT_SPECIES, a, i + PREF_FLOAT_SPECIES.length()); + FloatVector vd = + FloatVector.fromArray(PREF_FLOAT_SPECIES, b, i + PREF_FLOAT_SPECIES.length()); + acc2 = acc2.add(vc.mul(vd)); + FloatVector ve = + FloatVector.fromArray(PREF_FLOAT_SPECIES, a, i + 2 * PREF_FLOAT_SPECIES.length()); + FloatVector vf = + FloatVector.fromArray(PREF_FLOAT_SPECIES, b, i + 2 * PREF_FLOAT_SPECIES.length()); + acc3 = acc3.add(ve.mul(vf)); + FloatVector vg = + FloatVector.fromArray(PREF_FLOAT_SPECIES, a, i + 3 * PREF_FLOAT_SPECIES.length()); + FloatVector vh = + FloatVector.fromArray(PREF_FLOAT_SPECIES, b, i + 3 * PREF_FLOAT_SPECIES.length()); + acc4 = acc4.add(vg.mul(vh)); + } + // vector tail: less scalar computations for unaligned sizes, esp with big vector sizes + upperBound = PREF_FLOAT_SPECIES.loopBound(a.length); + for (; i < upperBound; i += PREF_FLOAT_SPECIES.length()) { + FloatVector va = FloatVector.fromArray(PREF_FLOAT_SPECIES, a, i); + FloatVector vb = FloatVector.fromArray(PREF_FLOAT_SPECIES, b, i); + acc1 = acc1.add(va.mul(vb)); + } + // reduce + FloatVector res1 = acc1.add(acc2); + FloatVector res2 = acc3.add(acc4); + res += res1.add(res2).reduceLanes(VectorOperators.ADD); + } + + for (; i < a.length; i++) { + res += b[i] * a[i]; + } + return res; + } + + @Override + public float cosine(float[] a, float[] b) { + int i = 0; + float sum = 0; + float norm1 = 0; + float norm2 = 0; + // if the array size is large (> 2x platform vector size), its worth the overhead to vectorize + if (a.length > 2 * PREF_FLOAT_SPECIES.length()) { + // vector loop is unrolled 4x (4 accumulators in parallel) + FloatVector sum1 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector sum2 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector sum3 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector sum4 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector norm1_1 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector norm1_2 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector norm1_3 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector norm1_4 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector norm2_1 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector norm2_2 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector norm2_3 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector norm2_4 = FloatVector.zero(PREF_FLOAT_SPECIES); + int upperBound = PREF_FLOAT_SPECIES.loopBound(a.length - 3 * PREF_FLOAT_SPECIES.length()); + for (; i < upperBound; i += 4 * PREF_FLOAT_SPECIES.length()) { + FloatVector va = FloatVector.fromArray(PREF_FLOAT_SPECIES, a, i); + FloatVector vb = FloatVector.fromArray(PREF_FLOAT_SPECIES, b, i); + sum1 = sum1.add(va.mul(vb)); + norm1_1 = norm1_1.add(va.mul(va)); + norm2_1 = norm2_1.add(vb.mul(vb)); + FloatVector vc = + FloatVector.fromArray(PREF_FLOAT_SPECIES, a, i + PREF_FLOAT_SPECIES.length()); + FloatVector vd = + FloatVector.fromArray(PREF_FLOAT_SPECIES, b, i + PREF_FLOAT_SPECIES.length()); + sum2 = sum2.add(vc.mul(vd)); + norm1_2 = norm1_2.add(vc.mul(vc)); + norm2_2 = norm2_2.add(vd.mul(vd)); + FloatVector ve = + FloatVector.fromArray(PREF_FLOAT_SPECIES, a, i + 2 * PREF_FLOAT_SPECIES.length()); + FloatVector vf = + FloatVector.fromArray(PREF_FLOAT_SPECIES, b, i + 2 * PREF_FLOAT_SPECIES.length()); + sum3 = sum3.add(ve.mul(vf)); + norm1_3 = norm1_3.add(ve.mul(ve)); + norm2_3 = norm2_3.add(vf.mul(vf)); + FloatVector vg = + FloatVector.fromArray(PREF_FLOAT_SPECIES, a, i + 3 * PREF_FLOAT_SPECIES.length()); + FloatVector vh = + FloatVector.fromArray(PREF_FLOAT_SPECIES, b, i + 3 * PREF_FLOAT_SPECIES.length()); + sum4 = sum4.add(vg.mul(vh)); + norm1_4 = norm1_4.add(vg.mul(vg)); + norm2_4 = norm2_4.add(vh.mul(vh)); + } + // vector tail: less scalar computations for unaligned sizes, esp with big vector sizes + upperBound = PREF_FLOAT_SPECIES.loopBound(a.length); + for (; i < upperBound; i += PREF_FLOAT_SPECIES.length()) { + FloatVector va = FloatVector.fromArray(PREF_FLOAT_SPECIES, a, i); + FloatVector vb = FloatVector.fromArray(PREF_FLOAT_SPECIES, b, i); + sum1 = sum1.add(va.mul(vb)); + norm1_1 = norm1_1.add(va.mul(va)); + norm2_1 = norm2_1.add(vb.mul(vb)); + } + // reduce + FloatVector sumres1 = sum1.add(sum2); + FloatVector sumres2 = sum3.add(sum4); + FloatVector norm1res1 = norm1_1.add(norm1_2); + FloatVector norm1res2 = norm1_3.add(norm1_4); + FloatVector norm2res1 = norm2_1.add(norm2_2); + FloatVector norm2res2 = norm2_3.add(norm2_4); + sum += sumres1.add(sumres2).reduceLanes(VectorOperators.ADD); + norm1 += norm1res1.add(norm1res2).reduceLanes(VectorOperators.ADD); + norm2 += norm2res1.add(norm2res2).reduceLanes(VectorOperators.ADD); + } + + for (; i < a.length; i++) { + float elem1 = a[i]; + float elem2 = b[i]; + sum += elem1 * elem2; + norm1 += elem1 * elem1; + norm2 += elem2 * elem2; + } + return (float) (sum / Math.sqrt((double) norm1 * (double) norm2)); + } + + @Override + public float squareDistance(float[] a, float[] b) { + int i = 0; + float res = 0; + // if the array size is large (> 2x platform vector size), its worth the overhead to vectorize + if (a.length > 2 * PREF_FLOAT_SPECIES.length()) { + // vector loop is unrolled 4x (4 accumulators in parallel) + FloatVector acc1 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector acc2 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector acc3 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector acc4 = FloatVector.zero(PREF_FLOAT_SPECIES); + int upperBound = PREF_FLOAT_SPECIES.loopBound(a.length - 3 * PREF_FLOAT_SPECIES.length()); + for (; i < upperBound; i += 4 * PREF_FLOAT_SPECIES.length()) { + FloatVector va = FloatVector.fromArray(PREF_FLOAT_SPECIES, a, i); + FloatVector vb = FloatVector.fromArray(PREF_FLOAT_SPECIES, b, i); + FloatVector diff1 = va.sub(vb); + acc1 = acc1.add(diff1.mul(diff1)); + FloatVector vc = + FloatVector.fromArray(PREF_FLOAT_SPECIES, a, i + PREF_FLOAT_SPECIES.length()); + FloatVector vd = + FloatVector.fromArray(PREF_FLOAT_SPECIES, b, i + PREF_FLOAT_SPECIES.length()); + FloatVector diff2 = vc.sub(vd); + acc2 = acc2.add(diff2.mul(diff2)); + FloatVector ve = + FloatVector.fromArray(PREF_FLOAT_SPECIES, a, i + 2 * PREF_FLOAT_SPECIES.length()); + FloatVector vf = + FloatVector.fromArray(PREF_FLOAT_SPECIES, b, i + 2 * PREF_FLOAT_SPECIES.length()); + FloatVector diff3 = ve.sub(vf); + acc3 = acc3.add(diff3.mul(diff3)); + FloatVector vg = + FloatVector.fromArray(PREF_FLOAT_SPECIES, a, i + 3 * PREF_FLOAT_SPECIES.length()); + FloatVector vh = + FloatVector.fromArray(PREF_FLOAT_SPECIES, b, i + 3 * PREF_FLOAT_SPECIES.length()); + FloatVector diff4 = vg.sub(vh); + acc4 = acc4.add(diff4.mul(diff4)); + } + // vector tail: less scalar computations for unaligned sizes, esp with big vector sizes + upperBound = PREF_FLOAT_SPECIES.loopBound(a.length); + for (; i < upperBound; i += PREF_FLOAT_SPECIES.length()) { + FloatVector va = FloatVector.fromArray(PREF_FLOAT_SPECIES, a, i); + FloatVector vb = FloatVector.fromArray(PREF_FLOAT_SPECIES, b, i); + FloatVector diff = va.sub(vb); + acc1 = acc1.add(diff.mul(diff)); + } + // reduce + FloatVector res1 = acc1.add(acc2); + FloatVector res2 = acc3.add(acc4); + res += res1.add(res2).reduceLanes(VectorOperators.ADD); + } + + for (; i < a.length; i++) { + float diff = a[i] - b[i]; + res += diff * diff; + } + return res; + } + + // Binary functions, these all follow a general pattern like this: + // + // short intermediate = a * b; + // int accumulator = accumulator + intermediate; + // + // 256 or 512 bit vectors can process 64 or 128 bits at a time, respectively + // intermediate results use 128 or 256 bit vectors, respectively + // final accumulator uses 256 or 512 bit vectors, respectively + // + // We also support 128 bit vectors, using two 128 bit accumulators. + // This is slower but still faster than not vectorizing at all. + + @Override + public int dotProduct(byte[] a, byte[] b) { + int i = 0; + int res = 0; + // only vectorize if we'll at least enter the loop a single time, and we have at least 128-bit + // vectors (256-bit on intel to dodge performance landmines) + if (a.length >= 16 && hasFastIntegerVectors) { + // compute vectorized dot product consistent with VPDPBUSD instruction + if (INT_SPECIES_PREF_BIT_SIZE >= 256) { + // optimized 256/512 bit implementation, processes 8/16 bytes at a time + int upperBound = PREF_BYTE_SPECIES.loopBound(a.length); + IntVector acc = IntVector.zero(IntVector.SPECIES_PREFERRED); + for (; i < upperBound; i += PREF_BYTE_SPECIES.length()) { + ByteVector va8 = ByteVector.fromArray(PREF_BYTE_SPECIES, a, i); + ByteVector vb8 = ByteVector.fromArray(PREF_BYTE_SPECIES, b, i); + Vector va16 = va8.convertShape(VectorOperators.B2S, PREF_SHORT_SPECIES, 0); + Vector vb16 = vb8.convertShape(VectorOperators.B2S, PREF_SHORT_SPECIES, 0); + Vector prod16 = va16.mul(vb16); + Vector prod32 = + prod16.convertShape(VectorOperators.S2I, IntVector.SPECIES_PREFERRED, 0); + acc = acc.add(prod32); + } + // reduce + res += acc.reduceLanes(VectorOperators.ADD); + } else { + // 128-bit implementation, which must "split up" vectors due to widening conversions + int upperBound = ByteVector.SPECIES_64.loopBound(a.length); + IntVector acc1 = IntVector.zero(IntVector.SPECIES_128); + IntVector acc2 = IntVector.zero(IntVector.SPECIES_128); + for (; i < upperBound; i += ByteVector.SPECIES_64.length()) { + ByteVector va8 = ByteVector.fromArray(ByteVector.SPECIES_64, a, i); + ByteVector vb8 = ByteVector.fromArray(ByteVector.SPECIES_64, b, i); + // expand each byte vector into short vector and multiply + Vector va16 = va8.convertShape(VectorOperators.B2S, ShortVector.SPECIES_128, 0); + Vector vb16 = vb8.convertShape(VectorOperators.B2S, ShortVector.SPECIES_128, 0); + Vector prod16 = va16.mul(vb16); + // split each short vector into two int vectors and add + Vector prod32_1 = + prod16.convertShape(VectorOperators.S2I, IntVector.SPECIES_128, 0); + Vector prod32_2 = + prod16.convertShape(VectorOperators.S2I, IntVector.SPECIES_128, 1); + acc1 = acc1.add(prod32_1); + acc2 = acc2.add(prod32_2); + } + // reduce + res += acc1.add(acc2).reduceLanes(VectorOperators.ADD); + } + } + + for (; i < a.length; i++) { + res += b[i] * a[i]; + } + return res; + } + + @Override + public float cosine(byte[] a, byte[] b) { + int i = 0; + int sum = 0; + int norm1 = 0; + int norm2 = 0; + // only vectorize if we'll at least enter the loop a single time, and we have at least 128-bit + // vectors (256-bit on intel to dodge performance landmines) + if (a.length >= 16 && hasFastIntegerVectors) { + if (INT_SPECIES_PREF_BIT_SIZE >= 256) { + // optimized 256/512 bit implementation, processes 8/16 bytes at a time + int upperBound = PREF_BYTE_SPECIES.loopBound(a.length); + IntVector accSum = IntVector.zero(IntVector.SPECIES_PREFERRED); + IntVector accNorm1 = IntVector.zero(IntVector.SPECIES_PREFERRED); + IntVector accNorm2 = IntVector.zero(IntVector.SPECIES_PREFERRED); + for (; i < upperBound; i += PREF_BYTE_SPECIES.length()) { + ByteVector va8 = ByteVector.fromArray(PREF_BYTE_SPECIES, a, i); + ByteVector vb8 = ByteVector.fromArray(PREF_BYTE_SPECIES, b, i); + Vector va16 = va8.convertShape(VectorOperators.B2S, PREF_SHORT_SPECIES, 0); + Vector vb16 = vb8.convertShape(VectorOperators.B2S, PREF_SHORT_SPECIES, 0); + Vector prod16 = va16.mul(vb16); + Vector norm1_16 = va16.mul(va16); + Vector norm2_16 = vb16.mul(vb16); + Vector prod32 = + prod16.convertShape(VectorOperators.S2I, IntVector.SPECIES_PREFERRED, 0); + Vector norm1_32 = + norm1_16.convertShape(VectorOperators.S2I, IntVector.SPECIES_PREFERRED, 0); + Vector norm2_32 = + norm2_16.convertShape(VectorOperators.S2I, IntVector.SPECIES_PREFERRED, 0); + accSum = accSum.add(prod32); + accNorm1 = accNorm1.add(norm1_32); + accNorm2 = accNorm2.add(norm2_32); + } + // reduce + sum += accSum.reduceLanes(VectorOperators.ADD); + norm1 += accNorm1.reduceLanes(VectorOperators.ADD); + norm2 += accNorm2.reduceLanes(VectorOperators.ADD); + } else { + // 128-bit implementation, which must "split up" vectors due to widening conversions + int upperBound = ByteVector.SPECIES_64.loopBound(a.length); + IntVector accSum1 = IntVector.zero(IntVector.SPECIES_128); + IntVector accSum2 = IntVector.zero(IntVector.SPECIES_128); + IntVector accNorm1_1 = IntVector.zero(IntVector.SPECIES_128); + IntVector accNorm1_2 = IntVector.zero(IntVector.SPECIES_128); + IntVector accNorm2_1 = IntVector.zero(IntVector.SPECIES_128); + IntVector accNorm2_2 = IntVector.zero(IntVector.SPECIES_128); + for (; i < upperBound; i += ByteVector.SPECIES_64.length()) { + ByteVector va8 = ByteVector.fromArray(ByteVector.SPECIES_64, a, i); + ByteVector vb8 = ByteVector.fromArray(ByteVector.SPECIES_64, b, i); + // expand each byte vector into short vector and perform multiplications + Vector va16 = va8.convertShape(VectorOperators.B2S, ShortVector.SPECIES_128, 0); + Vector vb16 = vb8.convertShape(VectorOperators.B2S, ShortVector.SPECIES_128, 0); + Vector prod16 = va16.mul(vb16); + Vector norm1_16 = va16.mul(va16); + Vector norm2_16 = vb16.mul(vb16); + // split each short vector into two int vectors and add + Vector prod32_1 = + prod16.convertShape(VectorOperators.S2I, IntVector.SPECIES_128, 0); + Vector prod32_2 = + prod16.convertShape(VectorOperators.S2I, IntVector.SPECIES_128, 1); + Vector norm1_32_1 = + norm1_16.convertShape(VectorOperators.S2I, IntVector.SPECIES_128, 0); + Vector norm1_32_2 = + norm1_16.convertShape(VectorOperators.S2I, IntVector.SPECIES_128, 1); + Vector norm2_32_1 = + norm2_16.convertShape(VectorOperators.S2I, IntVector.SPECIES_128, 0); + Vector norm2_32_2 = + norm2_16.convertShape(VectorOperators.S2I, IntVector.SPECIES_128, 1); + accSum1 = accSum1.add(prod32_1); + accSum2 = accSum2.add(prod32_2); + accNorm1_1 = accNorm1_1.add(norm1_32_1); + accNorm1_2 = accNorm1_2.add(norm1_32_2); + accNorm2_1 = accNorm2_1.add(norm2_32_1); + accNorm2_2 = accNorm2_2.add(norm2_32_2); + } + // reduce + sum += accSum1.add(accSum2).reduceLanes(VectorOperators.ADD); + norm1 += accNorm1_1.add(accNorm1_2).reduceLanes(VectorOperators.ADD); + norm2 += accNorm2_1.add(accNorm2_2).reduceLanes(VectorOperators.ADD); + } + } + + for (; i < a.length; i++) { + byte elem1 = a[i]; + byte elem2 = b[i]; + sum += elem1 * elem2; + norm1 += elem1 * elem1; + norm2 += elem2 * elem2; + } + return (float) (sum / Math.sqrt((double) norm1 * (double) norm2)); + } + + @Override + public int squareDistance(byte[] a, byte[] b) { + int i = 0; + int res = 0; + // only vectorize if we'll at least enter the loop a single time, and we have at least 128-bit + // vectors (256-bit on intel to dodge performance landmines) + if (a.length >= 16 && hasFastIntegerVectors) { + if (INT_SPECIES_PREF_BIT_SIZE >= 256) { + // optimized 256/512 bit implementation, processes 8/16 bytes at a time + int upperBound = PREF_BYTE_SPECIES.loopBound(a.length); + IntVector acc = IntVector.zero(IntVector.SPECIES_PREFERRED); + for (; i < upperBound; i += PREF_BYTE_SPECIES.length()) { + ByteVector va8 = ByteVector.fromArray(PREF_BYTE_SPECIES, a, i); + ByteVector vb8 = ByteVector.fromArray(PREF_BYTE_SPECIES, b, i); + Vector va16 = va8.convertShape(VectorOperators.B2S, PREF_SHORT_SPECIES, 0); + Vector vb16 = vb8.convertShape(VectorOperators.B2S, PREF_SHORT_SPECIES, 0); + Vector diff16 = va16.sub(vb16); + Vector diff32 = + diff16.convertShape(VectorOperators.S2I, IntVector.SPECIES_PREFERRED, 0); + acc = acc.add(diff32.mul(diff32)); + } + // reduce + res += acc.reduceLanes(VectorOperators.ADD); + } else { + // 128-bit implementation, which must "split up" vectors due to widening conversions + int upperBound = ByteVector.SPECIES_64.loopBound(a.length); + IntVector acc1 = IntVector.zero(IntVector.SPECIES_128); + IntVector acc2 = IntVector.zero(IntVector.SPECIES_128); + for (; i < upperBound; i += ByteVector.SPECIES_64.length()) { + ByteVector va8 = ByteVector.fromArray(ByteVector.SPECIES_64, a, i); + ByteVector vb8 = ByteVector.fromArray(ByteVector.SPECIES_64, b, i); + // expand each byte vector into short vector and subtract + Vector va16 = va8.convertShape(VectorOperators.B2S, ShortVector.SPECIES_128, 0); + Vector vb16 = vb8.convertShape(VectorOperators.B2S, ShortVector.SPECIES_128, 0); + Vector diff16 = va16.sub(vb16); + // split each short vector into two int vectors, square, and add + Vector diff32_1 = + diff16.convertShape(VectorOperators.S2I, IntVector.SPECIES_128, 0); + Vector diff32_2 = + diff16.convertShape(VectorOperators.S2I, IntVector.SPECIES_128, 1); + acc1 = acc1.add(diff32_1.mul(diff32_1)); + acc2 = acc2.add(diff32_2.mul(diff32_2)); + } + // reduce + res += acc1.add(acc2).reduceLanes(VectorOperators.ADD); + } + } + + for (; i < a.length; i++) { + int diff = a[i] - b[i]; + res += diff * diff; + } + return res; + } +} diff --git a/lucene/core/src/java21/org/apache/lucene/store/MemorySegmentIndexInput.java b/lucene/core/src/java21/org/apache/lucene/store/MemorySegmentIndexInput.java new file mode 100644 index 000000000000..7b2216add785 --- /dev/null +++ b/lucene/core/src/java21/org/apache/lucene/store/MemorySegmentIndexInput.java @@ -0,0 +1,588 @@ +/* + * 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.store; + +import java.io.EOFException; +import java.io.IOException; +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; +import java.nio.ByteOrder; +import java.util.Arrays; +import java.util.Objects; +import org.apache.lucene.util.ArrayUtil; + +/** + * Base IndexInput implementation that uses an array of MemorySegments to represent a file. + * + *

    For efficiency, this class requires that the segment size are a power-of-two ( + * chunkSizePower). + */ +@SuppressWarnings("preview") +abstract class MemorySegmentIndexInput extends IndexInput implements RandomAccessInput { + static final ValueLayout.OfByte LAYOUT_BYTE = ValueLayout.JAVA_BYTE; + static final ValueLayout.OfShort LAYOUT_LE_SHORT = + ValueLayout.JAVA_SHORT_UNALIGNED.withOrder(ByteOrder.LITTLE_ENDIAN); + static final ValueLayout.OfInt LAYOUT_LE_INT = + ValueLayout.JAVA_INT_UNALIGNED.withOrder(ByteOrder.LITTLE_ENDIAN); + static final ValueLayout.OfLong LAYOUT_LE_LONG = + ValueLayout.JAVA_LONG_UNALIGNED.withOrder(ByteOrder.LITTLE_ENDIAN); + static final ValueLayout.OfFloat LAYOUT_LE_FLOAT = + ValueLayout.JAVA_FLOAT_UNALIGNED.withOrder(ByteOrder.LITTLE_ENDIAN); + + final long length; + final long chunkSizeMask; + final int chunkSizePower; + final Arena arena; + final MemorySegment[] segments; + + int curSegmentIndex = -1; + MemorySegment + curSegment; // redundant for speed: segments[curSegmentIndex], also marker if closed! + long curPosition; // relative to curSegment, not globally + + public static MemorySegmentIndexInput newInstance( + String resourceDescription, + Arena arena, + MemorySegment[] segments, + long length, + int chunkSizePower) { + assert Arrays.stream(segments).map(MemorySegment::scope).allMatch(arena.scope()::equals); + if (segments.length == 1) { + return new SingleSegmentImpl(resourceDescription, arena, segments[0], length, chunkSizePower); + } else { + return new MultiSegmentImpl(resourceDescription, arena, segments, 0, length, chunkSizePower); + } + } + + private MemorySegmentIndexInput( + String resourceDescription, + Arena arena, + MemorySegment[] segments, + long length, + int chunkSizePower) { + super(resourceDescription); + this.arena = arena; + this.segments = segments; + this.length = length; + this.chunkSizePower = chunkSizePower; + this.chunkSizeMask = (1L << chunkSizePower) - 1L; + this.curSegment = segments[0]; + } + + void ensureOpen() { + if (curSegment == null) { + throw alreadyClosed(null); + } + } + + // the unused parameter is just to silence javac about unused variables + RuntimeException handlePositionalIOOBE(RuntimeException unused, String action, long pos) + throws IOException { + if (pos < 0L) { + return new IllegalArgumentException(action + " negative position (pos=" + pos + "): " + this); + } else { + throw new EOFException(action + " past EOF (pos=" + pos + "): " + this); + } + } + + // the unused parameter is just to silence javac about unused variables + AlreadyClosedException alreadyClosed(RuntimeException unused) { + return new AlreadyClosedException("Already closed: " + this); + } + + @Override + public final byte readByte() throws IOException { + try { + final byte v = curSegment.get(LAYOUT_BYTE, curPosition); + curPosition++; + return v; + } catch ( + @SuppressWarnings("unused") + IndexOutOfBoundsException e) { + do { + curSegmentIndex++; + if (curSegmentIndex >= segments.length) { + throw new EOFException("read past EOF: " + this); + } + curSegment = segments[curSegmentIndex]; + curPosition = 0L; + } while (curSegment.byteSize() == 0L); + final byte v = curSegment.get(LAYOUT_BYTE, curPosition); + curPosition++; + return v; + } catch (NullPointerException | IllegalStateException e) { + throw alreadyClosed(e); + } + } + + @Override + public final void readBytes(byte[] b, int offset, int len) throws IOException { + try { + MemorySegment.copy(curSegment, LAYOUT_BYTE, curPosition, b, offset, len); + curPosition += len; + } catch ( + @SuppressWarnings("unused") + IndexOutOfBoundsException e) { + readBytesBoundary(b, offset, len); + } catch (NullPointerException | IllegalStateException e) { + throw alreadyClosed(e); + } + } + + private void readBytesBoundary(byte[] b, int offset, int len) throws IOException { + try { + long curAvail = curSegment.byteSize() - curPosition; + while (len > curAvail) { + MemorySegment.copy(curSegment, LAYOUT_BYTE, curPosition, b, offset, (int) curAvail); + len -= curAvail; + offset += curAvail; + curSegmentIndex++; + if (curSegmentIndex >= segments.length) { + throw new EOFException("read past EOF: " + this); + } + curSegment = segments[curSegmentIndex]; + curPosition = 0L; + curAvail = curSegment.byteSize(); + } + MemorySegment.copy(curSegment, LAYOUT_BYTE, curPosition, b, offset, len); + curPosition += len; + } catch (NullPointerException | IllegalStateException e) { + throw alreadyClosed(e); + } + } + + @Override + public void readInts(int[] dst, int offset, int length) throws IOException { + try { + MemorySegment.copy(curSegment, LAYOUT_LE_INT, curPosition, dst, offset, length); + curPosition += Integer.BYTES * (long) length; + } catch ( + @SuppressWarnings("unused") + IndexOutOfBoundsException iobe) { + super.readInts(dst, offset, length); + } catch (NullPointerException | IllegalStateException e) { + throw alreadyClosed(e); + } + } + + @Override + public void readLongs(long[] dst, int offset, int length) throws IOException { + try { + MemorySegment.copy(curSegment, LAYOUT_LE_LONG, curPosition, dst, offset, length); + curPosition += Long.BYTES * (long) length; + } catch ( + @SuppressWarnings("unused") + IndexOutOfBoundsException iobe) { + super.readLongs(dst, offset, length); + } catch (NullPointerException | IllegalStateException e) { + throw alreadyClosed(e); + } + } + + @Override + public void readFloats(float[] dst, int offset, int length) throws IOException { + try { + MemorySegment.copy(curSegment, LAYOUT_LE_FLOAT, curPosition, dst, offset, length); + curPosition += Float.BYTES * (long) length; + } catch ( + @SuppressWarnings("unused") + IndexOutOfBoundsException iobe) { + super.readFloats(dst, offset, length); + } catch (NullPointerException | IllegalStateException e) { + throw alreadyClosed(e); + } + } + + @Override + public final short readShort() throws IOException { + try { + final short v = curSegment.get(LAYOUT_LE_SHORT, curPosition); + curPosition += Short.BYTES; + return v; + } catch ( + @SuppressWarnings("unused") + IndexOutOfBoundsException e) { + return super.readShort(); + } catch (NullPointerException | IllegalStateException e) { + throw alreadyClosed(e); + } + } + + @Override + public final int readInt() throws IOException { + try { + final int v = curSegment.get(LAYOUT_LE_INT, curPosition); + curPosition += Integer.BYTES; + return v; + } catch ( + @SuppressWarnings("unused") + IndexOutOfBoundsException e) { + return super.readInt(); + } catch (NullPointerException | IllegalStateException e) { + throw alreadyClosed(e); + } + } + + @Override + public final long readLong() throws IOException { + try { + final long v = curSegment.get(LAYOUT_LE_LONG, curPosition); + curPosition += Long.BYTES; + return v; + } catch ( + @SuppressWarnings("unused") + IndexOutOfBoundsException e) { + return super.readLong(); + } catch (NullPointerException | IllegalStateException e) { + throw alreadyClosed(e); + } + } + + @Override + public long getFilePointer() { + ensureOpen(); + return (((long) curSegmentIndex) << chunkSizePower) + curPosition; + } + + @Override + public void seek(long pos) throws IOException { + ensureOpen(); + // we use >> here to preserve negative, so we will catch AIOOBE, + // in case pos + offset overflows. + final int si = (int) (pos >> chunkSizePower); + try { + if (si != curSegmentIndex) { + final MemorySegment seg = segments[si]; + // write values, on exception all is unchanged + this.curSegmentIndex = si; + this.curSegment = seg; + } + this.curPosition = Objects.checkIndex(pos & chunkSizeMask, curSegment.byteSize() + 1); + } catch (IndexOutOfBoundsException e) { + throw handlePositionalIOOBE(e, "seek", pos); + } + } + + @Override + public byte readByte(long pos) throws IOException { + try { + final int si = (int) (pos >> chunkSizePower); + return segments[si].get(LAYOUT_BYTE, pos & chunkSizeMask); + } catch (IndexOutOfBoundsException ioobe) { + throw handlePositionalIOOBE(ioobe, "read", pos); + } catch (NullPointerException | IllegalStateException e) { + throw alreadyClosed(e); + } + } + + // used only by random access methods to handle reads across boundaries + private void setPos(long pos, int si) throws IOException { + try { + final MemorySegment seg = segments[si]; + // write values, on exception above all is unchanged + this.curPosition = pos & chunkSizeMask; + this.curSegmentIndex = si; + this.curSegment = seg; + } catch (IndexOutOfBoundsException ioobe) { + throw handlePositionalIOOBE(ioobe, "read", pos); + } catch (NullPointerException | IllegalStateException e) { + throw alreadyClosed(e); + } + } + + @Override + public short readShort(long pos) throws IOException { + final int si = (int) (pos >> chunkSizePower); + try { + return segments[si].get(LAYOUT_LE_SHORT, pos & chunkSizeMask); + } catch ( + @SuppressWarnings("unused") + IndexOutOfBoundsException ioobe) { + // either it's a boundary, or read past EOF, fall back: + setPos(pos, si); + return readShort(); + } catch (NullPointerException | IllegalStateException e) { + throw alreadyClosed(e); + } + } + + @Override + public int readInt(long pos) throws IOException { + final int si = (int) (pos >> chunkSizePower); + try { + return segments[si].get(LAYOUT_LE_INT, pos & chunkSizeMask); + } catch ( + @SuppressWarnings("unused") + IndexOutOfBoundsException ioobe) { + // either it's a boundary, or read past EOF, fall back: + setPos(pos, si); + return readInt(); + } catch (NullPointerException | IllegalStateException e) { + throw alreadyClosed(e); + } + } + + @Override + public long readLong(long pos) throws IOException { + final int si = (int) (pos >> chunkSizePower); + try { + return segments[si].get(LAYOUT_LE_LONG, pos & chunkSizeMask); + } catch ( + @SuppressWarnings("unused") + IndexOutOfBoundsException ioobe) { + // either it's a boundary, or read past EOF, fall back: + setPos(pos, si); + return readLong(); + } catch (NullPointerException | IllegalStateException e) { + throw alreadyClosed(e); + } + } + + @Override + public final long length() { + return length; + } + + @Override + public final MemorySegmentIndexInput clone() { + final MemorySegmentIndexInput clone = buildSlice((String) null, 0L, this.length); + try { + clone.seek(getFilePointer()); + } catch (IOException ioe) { + throw new AssertionError(ioe); + } + + return clone; + } + + /** + * Creates a slice of this index input, with the given description, offset, and length. The slice + * is seeked to the beginning. + */ + @Override + public final MemorySegmentIndexInput slice(String sliceDescription, long offset, long length) { + if (offset < 0 || length < 0 || offset + length > this.length) { + throw new IllegalArgumentException( + "slice() " + + sliceDescription + + " out of bounds: offset=" + + offset + + ",length=" + + length + + ",fileLength=" + + this.length + + ": " + + this); + } + + return buildSlice(sliceDescription, offset, length); + } + + /** Builds the actual sliced IndexInput (may apply extra offset in subclasses). * */ + MemorySegmentIndexInput buildSlice(String sliceDescription, long offset, long length) { + ensureOpen(); + + final long sliceEnd = offset + length; + final int startIndex = (int) (offset >>> chunkSizePower); + final int endIndex = (int) (sliceEnd >>> chunkSizePower); + + // we always allocate one more slice, the last one may be a 0 byte one after truncating with + // asSlice(): + final MemorySegment slices[] = ArrayUtil.copyOfSubArray(segments, startIndex, endIndex + 1); + + // set the last segment's limit for the sliced view. + slices[slices.length - 1] = slices[slices.length - 1].asSlice(0L, sliceEnd & chunkSizeMask); + + offset = offset & chunkSizeMask; + + final String newResourceDescription = getFullSliceDescription(sliceDescription); + if (slices.length == 1) { + return new SingleSegmentImpl( + newResourceDescription, + null, // clones don't have an Arena, as they can't close) + slices[0].asSlice(offset, length), + length, + chunkSizePower); + } else { + return new MultiSegmentImpl( + newResourceDescription, + null, // clones don't have an Arena, as they can't close) + slices, + offset, + length, + chunkSizePower); + } + } + + @Override + public final void close() throws IOException { + if (curSegment == null) { + return; + } + + // make sure all accesses to this IndexInput instance throw NPE: + curSegment = null; + Arrays.fill(segments, null); + + // the master IndexInput has an Arena and is able + // to release all resources (unmap segments) - a + // side effect is that other threads still using clones + // will throw IllegalStateException + if (arena != null) { + arena.close(); + } + } + + /** Optimization of MemorySegmentIndexInput for when there is only one segment. */ + static final class SingleSegmentImpl extends MemorySegmentIndexInput { + + SingleSegmentImpl( + String resourceDescription, + Arena arena, + MemorySegment segment, + long length, + int chunkSizePower) { + super(resourceDescription, arena, new MemorySegment[] {segment}, length, chunkSizePower); + this.curSegmentIndex = 0; + } + + @Override + public void seek(long pos) throws IOException { + ensureOpen(); + try { + curPosition = Objects.checkIndex(pos, length + 1); + } catch (IndexOutOfBoundsException e) { + throw handlePositionalIOOBE(e, "seek", pos); + } + } + + @Override + public long getFilePointer() { + ensureOpen(); + return curPosition; + } + + @Override + public byte readByte(long pos) throws IOException { + try { + return curSegment.get(LAYOUT_BYTE, pos); + } catch (IndexOutOfBoundsException e) { + throw handlePositionalIOOBE(e, "read", pos); + } catch (NullPointerException | IllegalStateException e) { + throw alreadyClosed(e); + } + } + + @Override + public short readShort(long pos) throws IOException { + try { + return curSegment.get(LAYOUT_LE_SHORT, pos); + } catch (IndexOutOfBoundsException e) { + throw handlePositionalIOOBE(e, "read", pos); + } catch (NullPointerException | IllegalStateException e) { + throw alreadyClosed(e); + } + } + + @Override + public int readInt(long pos) throws IOException { + try { + return curSegment.get(LAYOUT_LE_INT, pos); + } catch (IndexOutOfBoundsException e) { + throw handlePositionalIOOBE(e, "read", pos); + } catch (NullPointerException | IllegalStateException e) { + throw alreadyClosed(e); + } + } + + @Override + public long readLong(long pos) throws IOException { + try { + return curSegment.get(LAYOUT_LE_LONG, pos); + } catch (IndexOutOfBoundsException e) { + throw handlePositionalIOOBE(e, "read", pos); + } catch (NullPointerException | IllegalStateException e) { + throw alreadyClosed(e); + } + } + } + + /** This class adds offset support to MemorySegmentIndexInput, which is needed for slices. */ + static final class MultiSegmentImpl extends MemorySegmentIndexInput { + private final long offset; + + MultiSegmentImpl( + String resourceDescription, + Arena arena, + MemorySegment[] segments, + long offset, + long length, + int chunkSizePower) { + super(resourceDescription, arena, segments, length, chunkSizePower); + this.offset = offset; + try { + seek(0L); + } catch (IOException ioe) { + throw new AssertionError(ioe); + } + assert curSegment != null && curSegmentIndex >= 0; + } + + @Override + RuntimeException handlePositionalIOOBE(RuntimeException unused, String action, long pos) + throws IOException { + return super.handlePositionalIOOBE(unused, action, pos - offset); + } + + @Override + public void seek(long pos) throws IOException { + assert pos >= 0L : "negative position"; + super.seek(pos + offset); + } + + @Override + public long getFilePointer() { + return super.getFilePointer() - offset; + } + + @Override + public byte readByte(long pos) throws IOException { + return super.readByte(pos + offset); + } + + @Override + public short readShort(long pos) throws IOException { + return super.readShort(pos + offset); + } + + @Override + public int readInt(long pos) throws IOException { + return super.readInt(pos + offset); + } + + @Override + public long readLong(long pos) throws IOException { + return super.readLong(pos + offset); + } + + @Override + MemorySegmentIndexInput buildSlice(String sliceDescription, long ofs, long length) { + return super.buildSlice(sliceDescription, this.offset + ofs, length); + } + } +} diff --git a/lucene/core/src/java21/org/apache/lucene/store/MemorySegmentIndexInputProvider.java b/lucene/core/src/java21/org/apache/lucene/store/MemorySegmentIndexInputProvider.java new file mode 100644 index 000000000000..e994c2dddfff --- /dev/null +++ b/lucene/core/src/java21/org/apache/lucene/store/MemorySegmentIndexInputProvider.java @@ -0,0 +1,120 @@ +/* + * 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.store; + +import java.io.IOException; +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.nio.channels.FileChannel; +import java.nio.channels.FileChannel.MapMode; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.logging.Logger; +import org.apache.lucene.util.Constants; +import org.apache.lucene.util.Unwrappable; + +@SuppressWarnings("preview") +final class MemorySegmentIndexInputProvider implements MMapDirectory.MMapIndexInputProvider { + + public MemorySegmentIndexInputProvider() { + var log = Logger.getLogger(getClass().getName()); + log.info( + "Using MemorySegmentIndexInput with Java 21; to disable start with -D" + + MMapDirectory.ENABLE_MEMORY_SEGMENTS_SYSPROP + + "=false"); + } + + @Override + public IndexInput openInput(Path path, IOContext context, int chunkSizePower, boolean preload) + throws IOException { + final String resourceDescription = "MemorySegmentIndexInput(path=\"" + path.toString() + "\")"; + + // Work around for JDK-8259028: we need to unwrap our test-only file system layers + path = Unwrappable.unwrapAll(path); + + boolean success = false; + final Arena arena = Arena.ofShared(); + try (var fc = FileChannel.open(path, StandardOpenOption.READ)) { + final long fileSize = fc.size(); + final IndexInput in = + MemorySegmentIndexInput.newInstance( + resourceDescription, + arena, + map(arena, resourceDescription, fc, chunkSizePower, preload, fileSize), + fileSize, + chunkSizePower); + success = true; + return in; + } finally { + if (success == false) { + arena.close(); + } + } + } + + @Override + public long getDefaultMaxChunkSize() { + return Constants.JRE_IS_64BIT ? (1L << 34) : (1L << 28); + } + + @Override + public boolean isUnmapSupported() { + return true; + } + + @Override + public String getUnmapNotSupportedReason() { + return null; + } + + private final MemorySegment[] map( + Arena arena, + String resourceDescription, + FileChannel fc, + int chunkSizePower, + boolean preload, + long length) + throws IOException { + if ((length >>> chunkSizePower) >= Integer.MAX_VALUE) + throw new IllegalArgumentException("File too big for chunk size: " + resourceDescription); + + final long chunkSize = 1L << chunkSizePower; + + // we always allocate one more segments, the last one may be a 0 byte one + final int nrSegments = (int) (length >>> chunkSizePower) + 1; + + final MemorySegment[] segments = new MemorySegment[nrSegments]; + + long startOffset = 0L; + for (int segNr = 0; segNr < nrSegments; segNr++) { + final long segSize = + (length > (startOffset + chunkSize)) ? chunkSize : (length - startOffset); + final MemorySegment segment; + try { + segment = fc.map(MapMode.READ_ONLY, startOffset, segSize, arena); + } catch (IOException ioe) { + throw convertMapFailedIOException(ioe, resourceDescription, segSize); + } + if (preload) { + segment.load(); + } + segments[segNr] = segment; + startOffset += segSize; + } + return segments; + } +} diff --git a/lucene/core/src/java21/org/apache/lucene/util/VectorUtilPanamaProvider.txt b/lucene/core/src/java21/org/apache/lucene/util/VectorUtilPanamaProvider.txt new file mode 100644 index 000000000000..db75951206ef --- /dev/null +++ b/lucene/core/src/java21/org/apache/lucene/util/VectorUtilPanamaProvider.txt @@ -0,0 +1,2 @@ +The version of VectorUtilPanamaProvider for Java 21 is identical to that of Java 20. +As such, there is no specific 21 version - the Java 20 version will be loaded from the MRJAR. \ No newline at end of file diff --git a/lucene/core/src/test/org/apache/lucene/analysis/TestAutomatonToTokenStream.java b/lucene/core/src/test/org/apache/lucene/analysis/TestAutomatonToTokenStream.java index 27d2c72ddb09..d558ad6d3697 100644 --- a/lucene/core/src/test/org/apache/lucene/analysis/TestAutomatonToTokenStream.java +++ b/lucene/core/src/test/org/apache/lucene/analysis/TestAutomatonToTokenStream.java @@ -22,8 +22,8 @@ import java.util.List; import org.apache.lucene.tests.analysis.BaseTokenStreamTestCase; import org.apache.lucene.util.BytesRef; +import org.apache.lucene.util.automaton.Automata; import org.apache.lucene.util.automaton.Automaton; -import org.apache.lucene.util.automaton.DaciukMihovAutomatonBuilder; public class TestAutomatonToTokenStream extends BaseTokenStreamTestCase { @@ -31,7 +31,7 @@ public void testSinglePath() throws IOException { List acceptStrings = new ArrayList<>(); acceptStrings.add(new BytesRef("abc")); - Automaton flatPathAutomaton = DaciukMihovAutomatonBuilder.build(acceptStrings); + Automaton flatPathAutomaton = Automata.makeStringUnion(acceptStrings); TokenStream ts = AutomatonToTokenStream.toTokenStream(flatPathAutomaton); assertTokenStreamContents( ts, @@ -48,7 +48,7 @@ public void testParallelPaths() throws IOException { acceptStrings.add(new BytesRef("123")); acceptStrings.add(new BytesRef("abc")); - Automaton flatPathAutomaton = DaciukMihovAutomatonBuilder.build(acceptStrings); + Automaton flatPathAutomaton = Automata.makeStringUnion(acceptStrings); TokenStream ts = AutomatonToTokenStream.toTokenStream(flatPathAutomaton); assertTokenStreamContents( ts, @@ -65,7 +65,7 @@ public void testForkedPath() throws IOException { acceptStrings.add(new BytesRef("ab3")); acceptStrings.add(new BytesRef("abc")); - Automaton flatPathAutomaton = DaciukMihovAutomatonBuilder.build(acceptStrings); + Automaton flatPathAutomaton = Automata.makeStringUnion(acceptStrings); TokenStream ts = AutomatonToTokenStream.toTokenStream(flatPathAutomaton); assertTokenStreamContents( ts, diff --git a/lucene/core/src/test/org/apache/lucene/analysis/TestWordlistLoader.java b/lucene/core/src/test/org/apache/lucene/analysis/TestWordlistLoader.java index 7af64c0011eb..4747c86834ed 100644 --- a/lucene/core/src/test/org/apache/lucene/analysis/TestWordlistLoader.java +++ b/lucene/core/src/test/org/apache/lucene/analysis/TestWordlistLoader.java @@ -24,7 +24,7 @@ public class TestWordlistLoader extends LuceneTestCase { public void testWordlistLoading() throws IOException { - String s = "ONE\n two \nthree"; + String s = "ONE\n two \nthree\n\n"; CharArraySet wordSet1 = WordlistLoader.getWordSet(new StringReader(s)); checkSet(wordSet1); CharArraySet wordSet2 = WordlistLoader.getWordSet(new BufferedReader(new StringReader(s))); diff --git a/lucene/core/src/test/org/apache/lucene/geo/TestTessellator.java b/lucene/core/src/test/org/apache/lucene/geo/TestTessellator.java index 950772f32b75..44c17b48440c 100644 --- a/lucene/core/src/test/org/apache/lucene/geo/TestTessellator.java +++ b/lucene/core/src/test/org/apache/lucene/geo/TestTessellator.java @@ -915,6 +915,28 @@ public void testComplexPolygon54() throws Exception { } } + public void testComplexPolygon55() throws Exception { + String geoJson = GeoTestUtil.readShape("github-12352-1.geojson.gz"); + Polygon[] polygons = Polygon.fromGeoJSON(geoJson); + for (Polygon polygon : polygons) { + List tessellation = + Tessellator.tessellate(polygon, random().nextBoolean()); + assertEquals(area(polygon), area(tessellation), 0.0); + // don't check edges as it takes several minutes + } + } + + public void testComplexPolygon56() throws Exception { + String geoJson = GeoTestUtil.readShape("github-12352-2.geojson.gz"); + Polygon[] polygons = Polygon.fromGeoJSON(geoJson); + for (Polygon polygon : polygons) { + List tessellation = + Tessellator.tessellate(polygon, random().nextBoolean()); + assertEquals(area(polygon), area(tessellation), 0.0); + // don't check edges as it takes several minutes + } + } + private static class TestCountingMonitor implements Tessellator.Monitor { private int count = 0; private int splitsStarted = 0; diff --git a/lucene/core/src/test/org/apache/lucene/index/TestCachingMergeContext.java b/lucene/core/src/test/org/apache/lucene/index/TestCachingMergeContext.java new file mode 100644 index 000000000000..3210d54540d7 --- /dev/null +++ b/lucene/core/src/test/org/apache/lucene/index/TestCachingMergeContext.java @@ -0,0 +1,69 @@ +/* + * 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.index; + +import java.io.IOException; +import java.util.Set; +import org.apache.lucene.tests.util.LuceneTestCase; +import org.apache.lucene.util.InfoStream; + +public class TestCachingMergeContext extends LuceneTestCase { + public void testNumDeletesToMerge() throws IOException { + MockMergeContext mergeContext = new MockMergeContext(); + CachingMergeContext cachingMergeContext = new CachingMergeContext(mergeContext); + assertEquals(cachingMergeContext.numDeletesToMerge(null), 1); + assertEquals(cachingMergeContext.cachedNumDeletesToMerge.size(), 1); + assertEquals( + cachingMergeContext.cachedNumDeletesToMerge.getOrDefault(null, -1), Integer.valueOf(1)); + assertEquals(mergeContext.count, 1); + + // increase the mock count + mergeContext.numDeletesToMerge(null); + assertEquals(mergeContext.count, 2); + + // assert the cache result still one + assertEquals(cachingMergeContext.numDeletesToMerge(null), 1); + assertEquals(cachingMergeContext.cachedNumDeletesToMerge.size(), 1); + assertEquals( + cachingMergeContext.cachedNumDeletesToMerge.getOrDefault(null, -1), Integer.valueOf(1)); + } + + private static final class MockMergeContext implements MergePolicy.MergeContext { + int count = 0; + + @Override + public final int numDeletesToMerge(SegmentCommitInfo info) throws IOException { + this.count += 1; + return this.count; + } + + @Override + public int numDeletedDocs(SegmentCommitInfo info) { + return 0; + } + + @Override + public InfoStream getInfoStream() { + return null; + } + + @Override + public Set getMergingSegments() { + return null; + } + } +} diff --git a/lucene/core/src/test/org/apache/lucene/index/TestExitableDirectoryReader.java b/lucene/core/src/test/org/apache/lucene/index/TestExitableDirectoryReader.java index 5dc11a52fb49..4a6365b53094 100644 --- a/lucene/core/src/test/org/apache/lucene/index/TestExitableDirectoryReader.java +++ b/lucene/core/src/test/org/apache/lucene/index/TestExitableDirectoryReader.java @@ -40,6 +40,7 @@ import org.apache.lucene.tests.analysis.MockAnalyzer; import org.apache.lucene.tests.util.LuceneTestCase; import org.apache.lucene.util.BytesRef; +import org.apache.lucene.util.TestVectorUtil; /** * Test that uses a default/lucene Implementation of {@link QueryTimeout} to exit out long running @@ -463,13 +464,21 @@ public void testVectorValues() throws IOException { ExitingReaderException.class, () -> leaf.searchNearestVectors( - "vector", new float[dimension], 5, leaf.getLiveDocs(), Integer.MAX_VALUE)); + "vector", + TestVectorUtil.randomVector(dimension), + 5, + leaf.getLiveDocs(), + Integer.MAX_VALUE)); } else { DocIdSetIterator iter = leaf.getFloatVectorValues("vector"); scanAndRetrieve(leaf, iter); leaf.searchNearestVectors( - "vector", new float[dimension], 5, leaf.getLiveDocs(), Integer.MAX_VALUE); + "vector", + TestVectorUtil.randomVector(dimension), + 5, + leaf.getLiveDocs(), + Integer.MAX_VALUE); } reader.close(); diff --git a/lucene/core/src/test/org/apache/lucene/index/TestFieldInfo.java b/lucene/core/src/test/org/apache/lucene/index/TestFieldInfo.java new file mode 100644 index 000000000000..42f2c55fbf88 --- /dev/null +++ b/lucene/core/src/test/org/apache/lucene/index/TestFieldInfo.java @@ -0,0 +1,316 @@ +/* + * 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.index; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import org.apache.lucene.tests.util.LuceneTestCase; + +public class TestFieldInfo extends LuceneTestCase { + + public void testHandleLegacySupportedUpdatesValidIndexInfoChange() { + + FieldInfo fi1 = new FieldInfoTestBuilder().setIndexOptions(IndexOptions.NONE).get(); + FieldInfo fi2 = new FieldInfoTestBuilder().setOmitNorms(true).setStoreTermVector(false).get(); + + FieldInfo updatedFi = fi1.handleLegacySupportedUpdates(fi2); + assertNotNull(updatedFi); + assertEquals(updatedFi.getIndexOptions(), IndexOptions.DOCS); + assertFalse( + updatedFi + .hasNorms()); // fi2 is set to omitNorms and fi1 was not indexed, it's OK that the final + // FieldInfo returns hasNorms == false + compareAttributes(fi1, fi2, Set.of("getIndexOptions", "hasNorms")); + compareAttributes(fi1, updatedFi, Set.of("getIndexOptions", "hasNorms")); + compareAttributes(fi2, updatedFi, Set.of()); + + // The reverse return null since fi2 wouldn't change + assertNull(fi2.handleLegacySupportedUpdates(fi1)); + } + + public void testHandleLegacySupportedUpdatesInvalidIndexInfoChange() { + FieldInfo fi1 = new FieldInfoTestBuilder().setIndexOptions(IndexOptions.DOCS).get(); + FieldInfo fi2 = + new FieldInfoTestBuilder().setIndexOptions(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS).get(); + assertThrows(IllegalArgumentException.class, () -> fi1.handleLegacySupportedUpdates(fi2)); + assertThrows(IllegalArgumentException.class, () -> fi2.handleLegacySupportedUpdates(fi1)); + } + + public void testHandleLegacySupportedUpdatesValidPointDimensionCount() { + FieldInfo fi1 = new FieldInfoTestBuilder().get(); + FieldInfo fi2 = new FieldInfoTestBuilder().setPointDimensionCount(2).setPointNumBytes(2).get(); + FieldInfo updatedFi = fi1.handleLegacySupportedUpdates(fi2); + assertNotNull(updatedFi); + assertEquals(2, updatedFi.getPointDimensionCount()); + compareAttributes(fi1, fi2, Set.of("getPointDimensionCount", "getPointNumBytes")); + compareAttributes(fi1, updatedFi, Set.of("getPointDimensionCount", "getPointNumBytes")); + compareAttributes(fi2, updatedFi, Set.of()); + + // The reverse return null since fi2 wouldn't change + assertNull(fi2.handleLegacySupportedUpdates(fi1)); + } + + public void testHandleLegacySupportedUpdatesInvalidPointDimensionCount() { + FieldInfo fi1 = new FieldInfoTestBuilder().setPointDimensionCount(3).setPointNumBytes(2).get(); + FieldInfo fi2 = new FieldInfoTestBuilder().setPointDimensionCount(2).setPointNumBytes(2).get(); + FieldInfo fi3 = new FieldInfoTestBuilder().setPointDimensionCount(2).setPointNumBytes(3).get(); + assertThrows(IllegalArgumentException.class, () -> fi1.handleLegacySupportedUpdates(fi2)); + assertThrows(IllegalArgumentException.class, () -> fi2.handleLegacySupportedUpdates(fi1)); + + assertThrows(IllegalArgumentException.class, () -> fi1.handleLegacySupportedUpdates(fi3)); + assertThrows(IllegalArgumentException.class, () -> fi3.handleLegacySupportedUpdates(fi1)); + + assertThrows(IllegalArgumentException.class, () -> fi2.handleLegacySupportedUpdates(fi3)); + assertThrows(IllegalArgumentException.class, () -> fi3.handleLegacySupportedUpdates(fi2)); + } + + public void testHandleLegacySupportedUpdatesValidPointIndexDimensionCount() { + FieldInfo fi1 = new FieldInfoTestBuilder().get(); + FieldInfo fi2 = + new FieldInfoTestBuilder() + .setPointIndexDimensionCount(2) + .setPointDimensionCount(2) + .setPointNumBytes(2) + .get(); + FieldInfo updatedFi = fi1.handleLegacySupportedUpdates(fi2); + assertNotNull(updatedFi); + assertEquals(2, updatedFi.getPointDimensionCount()); + compareAttributes( + fi1, + fi2, + Set.of("getPointDimensionCount", "getPointNumBytes", "getPointIndexDimensionCount")); + compareAttributes( + fi1, + updatedFi, + Set.of("getPointDimensionCount", "getPointNumBytes", "getPointIndexDimensionCount")); + compareAttributes(fi2, updatedFi, Set.of()); + + // The reverse return null since fi2 wouldn't change + assertNull(fi2.handleLegacySupportedUpdates(fi1)); + } + + public void testHandleLegacySupportedUpdatesInvalidPointIndexDimensionCount() { + FieldInfo fi1 = + new FieldInfoTestBuilder() + .setPointDimensionCount(2) + .setPointIndexDimensionCount(2) + .setPointNumBytes(2) + .get(); + FieldInfo fi2 = + new FieldInfoTestBuilder() + .setPointDimensionCount(2) + .setPointIndexDimensionCount(3) + .setPointNumBytes(2) + .get(); + assertThrows(IllegalArgumentException.class, () -> fi1.handleLegacySupportedUpdates(fi2)); + assertThrows(IllegalArgumentException.class, () -> fi2.handleLegacySupportedUpdates(fi1)); + } + + public void testHandleLegacySupportedUpdatesValidStoreTermVectors() { + FieldInfo fi1 = new FieldInfoTestBuilder().setStoreTermVector(false).get(); + FieldInfo fi2 = new FieldInfoTestBuilder().setStoreTermVector(true).get(); + FieldInfo updatedFi = fi1.handleLegacySupportedUpdates(fi2); + assertNotNull(updatedFi); + assertTrue(updatedFi.hasVectors()); + compareAttributes(fi1, fi2, Set.of("hasVectors")); + compareAttributes(fi1, updatedFi, Set.of("hasVectors")); + compareAttributes(fi2, updatedFi, Set.of()); + + // The reverse return null since fi2 wouldn't change + assertNull(fi2.handleLegacySupportedUpdates(fi1)); + } + + public void testHandleLegacySupportedUpdatesValidStorePayloads() { + FieldInfo fi1 = + new FieldInfoTestBuilder() + .setStorePayloads(false) + .setIndexOptions(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS) + .get(); + FieldInfo fi2 = + new FieldInfoTestBuilder() + .setStorePayloads(true) + .setIndexOptions(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS) + .get(); + FieldInfo updatedFi = fi1.handleLegacySupportedUpdates(fi2); + assertNotNull(updatedFi); + assertTrue(updatedFi.hasPayloads()); + compareAttributes(fi1, fi2, Set.of("hasPayloads")); + compareAttributes(fi1, updatedFi, Set.of("hasPayloads")); + compareAttributes(fi2, updatedFi, Set.of()); + + // The reverse return null since fi2 wouldn't change + assertNull(fi2.handleLegacySupportedUpdates(fi1)); + } + + public void testHandleLegacySupportedUpdatesValidOmitNorms() { + FieldInfo fi1 = + new FieldInfoTestBuilder().setIndexOptions(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS).get(); + FieldInfo fi2 = + new FieldInfoTestBuilder() + .setIndexOptions(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS) + .setOmitNorms(true) + .get(); + FieldInfo updatedFi = fi1.handleLegacySupportedUpdates(fi2); + assertNotNull(updatedFi); + assertFalse(updatedFi.hasNorms()); // Once norms are omitted, they are always omitted + compareAttributes(fi1, fi2, Set.of("hasNorms")); + compareAttributes(fi1, updatedFi, Set.of("hasNorms")); + compareAttributes(fi2, updatedFi, Set.of()); + + // The reverse return null since fi2 wouldn't change + assertNull(fi2.handleLegacySupportedUpdates(fi1)); + } + + public void testHandleLegacySupportedUpdatesValidDocValuesType() { + + FieldInfo fi1 = new FieldInfoTestBuilder().get(); + FieldInfo fi2 = new FieldInfoTestBuilder().setDocValues(DocValuesType.SORTED).setDvGen(1).get(); + + FieldInfo updatedFi = fi1.handleLegacySupportedUpdates(fi2); + assertNotNull(updatedFi); + assertEquals(DocValuesType.SORTED, updatedFi.getDocValuesType()); + assertEquals(1, updatedFi.getDocValuesGen()); + compareAttributes(fi1, fi2, Set.of("getDocValuesType", "getDocValuesGen")); + compareAttributes(fi1, updatedFi, Set.of("getDocValuesType", "getDocValuesGen")); + compareAttributes(fi2, updatedFi, Set.of()); + + // The reverse return null since fi2 wouldn't change + assertNull(fi2.handleLegacySupportedUpdates(fi1)); + + FieldInfo fi3 = new FieldInfoTestBuilder().setDocValues(DocValuesType.SORTED).setDvGen(2).get(); + // Changes in DocValues Generation only are ignored + assertNull(fi2.handleLegacySupportedUpdates(fi3)); + assertNull(fi3.handleLegacySupportedUpdates(fi2)); + } + + public void testHandleLegacySupportedUpdatesInvalidDocValuesTypeChange() { + FieldInfo fi1 = new FieldInfoTestBuilder().setDocValues(DocValuesType.SORTED).get(); + FieldInfo fi2 = new FieldInfoTestBuilder().setDocValues(DocValuesType.SORTED_SET).get(); + assertThrows(IllegalArgumentException.class, () -> fi1.handleLegacySupportedUpdates(fi2)); + assertThrows(IllegalArgumentException.class, () -> fi2.handleLegacySupportedUpdates(fi1)); + } + + private static class FieldInfoTestBuilder { + String name = "f1"; + int number = 1; + boolean storeTermVector = true; + boolean omitNorms = false; + boolean storePayloads = false; + IndexOptions indexOptions = IndexOptions.DOCS; + DocValuesType docValues = DocValuesType.NONE; + long dvGen = -1; + Map attributes = new HashMap<>(); + int pointDimensionCount = 0; + int pointIndexDimensionCount = 0; + int pointNumBytes = 0; + int vectorDimension = 10; + VectorEncoding vectorEncoding = VectorEncoding.FLOAT32; + VectorSimilarityFunction vectorSimilarityFunction = VectorSimilarityFunction.EUCLIDEAN; + boolean softDeletesField = false; + + FieldInfo get() { + return new FieldInfo( + name, + number, + storeTermVector, + omitNorms, + storePayloads, + indexOptions, + docValues, + dvGen, + attributes, + pointDimensionCount, + pointIndexDimensionCount, + pointNumBytes, + vectorDimension, + vectorEncoding, + vectorSimilarityFunction, + softDeletesField); + } + + public FieldInfoTestBuilder setStoreTermVector(boolean storeTermVector) { + this.storeTermVector = storeTermVector; + return this; + } + + public FieldInfoTestBuilder setOmitNorms(boolean omitNorms) { + this.omitNorms = omitNorms; + return this; + } + + public FieldInfoTestBuilder setStorePayloads(boolean storePayloads) { + this.storePayloads = storePayloads; + return this; + } + + public FieldInfoTestBuilder setIndexOptions(IndexOptions indexOptions) { + this.indexOptions = indexOptions; + return this; + } + + public FieldInfoTestBuilder setDocValues(DocValuesType docValues) { + this.docValues = docValues; + return this; + } + + public FieldInfoTestBuilder setDvGen(long dvGen) { + this.dvGen = dvGen; + return this; + } + + public FieldInfoTestBuilder setPointDimensionCount(int pointDimensionCount) { + this.pointDimensionCount = pointDimensionCount; + return this; + } + + public FieldInfoTestBuilder setPointIndexDimensionCount(int pointIndexDimensionCount) { + this.pointIndexDimensionCount = pointIndexDimensionCount; + return this; + } + + public FieldInfoTestBuilder setPointNumBytes(int pointNumBytes) { + this.pointNumBytes = pointNumBytes; + return this; + } + } + + private void compareAttributes(FieldInfo fi1, FieldInfo fi2, Set exclude) { + assertNotNull(fi1); + assertNotNull(fi2); + Arrays.stream(FieldInfo.class.getMethods()) + .filter( + m -> + (m.getName().startsWith("get") || m.getName().startsWith("has")) + && !m.getName().equals("hashCode") + && !exclude.contains(m.getName()) + && m.getParameterCount() == 0) + .forEach( + m -> { + try { + assertEquals( + "Unexpected difference in FieldInfo for method: " + m.getName(), + m.invoke(fi1), + m.invoke(fi2)); + } catch (Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } + }); + } +} diff --git a/lucene/core/src/test/org/apache/lucene/index/TestFieldInfos.java b/lucene/core/src/test/org/apache/lucene/index/TestFieldInfos.java index b5a9ac5034b7..a4272cf56334 100644 --- a/lucene/core/src/test/org/apache/lucene/index/TestFieldInfos.java +++ b/lucene/core/src/test/org/apache/lucene/index/TestFieldInfos.java @@ -361,4 +361,43 @@ public void testRelaxConsistencyCheckForOldIndices() throws IOException { } } } + + public void testFieldInfosMergeBehaviorOnOldIndices() throws IOException { + try (Directory dir = newDirectory()) { + IndexWriterConfig config = + new IndexWriterConfig() + .setIndexCreatedVersionMajor(8) + .setMergeScheduler(new SerialMergeScheduler()) + .setOpenMode(IndexWriterConfig.OpenMode.CREATE); + FieldType ft1 = new FieldType(); + ft1.setIndexOptions(IndexOptions.NONE); + ft1.setStored(true); + FieldType ft2 = new FieldType(); + ft2.setIndexOptions(IndexOptions.DOCS); + ft2.setStored(true); + + try (IndexWriter writer = new IndexWriter(dir, config)) { + Document d1 = new Document(); + // Document 1 has my_field with IndexOptions.NONE + d1.add(new Field("my_field", "first", ft1)); + writer.addDocument(d1); + for (int i = 0; i < 100; i++) { + // Add some more docs to make sure segment 0 is the biggest one + Document d = new Document(); + d.add(new Field("foo", "bar" + i, ft2)); + writer.addDocument(d); + } + writer.flush(); + + Document d2 = new Document(); + // Document 2 has my_field with IndexOptions.DOCS + d2.add(new Field("my_field", "first", ft2)); + writer.addDocument(d2); + writer.flush(); + + writer.commit(); + writer.forceMerge(1); + } + } + } } diff --git a/lucene/core/src/test/org/apache/lucene/index/TestIndexWriter.java b/lucene/core/src/test/org/apache/lucene/index/TestIndexWriter.java index e9a2fd9141dd..9c7b7c8a5290 100644 --- a/lucene/core/src/test/org/apache/lucene/index/TestIndexWriter.java +++ b/lucene/core/src/test/org/apache/lucene/index/TestIndexWriter.java @@ -3473,7 +3473,12 @@ public int numDeletesToMerge( Document doc = new Document(); doc.add(new StringField("id", id, Field.Store.YES)); if (mixDeletes && random().nextBoolean()) { - writer.updateDocuments(new Term("id", id), Arrays.asList(doc, doc)); + if (random().nextBoolean()) { + writer.updateDocuments(new Term("id", id), Arrays.asList(doc, doc)); + } else { + writer.updateDocuments( + new TermQuery(new Term("id", id)), Arrays.asList(doc, doc)); + } } else { writer.softUpdateDocuments( new Term("id", id), diff --git a/lucene/core/src/test/org/apache/lucene/index/TestKnnGraph.java b/lucene/core/src/test/org/apache/lucene/index/TestKnnGraph.java index 08f089430ba5..372384df5572 100644 --- a/lucene/core/src/test/org/apache/lucene/index/TestKnnGraph.java +++ b/lucene/core/src/test/org/apache/lucene/index/TestKnnGraph.java @@ -54,6 +54,7 @@ import org.apache.lucene.util.VectorUtil; import org.apache.lucene.util.hnsw.HnswGraph; import org.apache.lucene.util.hnsw.HnswGraph.NodesIterator; +import org.apache.lucene.util.hnsw.HnswGraphBuilder; import org.junit.After; import org.junit.Before; @@ -62,7 +63,7 @@ public class TestKnnGraph extends LuceneTestCase { private static final String KNN_GRAPH_FIELD = "vector"; - private static int M = Lucene95HnswVectorsFormat.DEFAULT_MAX_CONN; + private static int M = HnswGraphBuilder.DEFAULT_MAX_CONN; private Codec codec; private Codec float32Codec; @@ -80,7 +81,7 @@ public void setup() { new Lucene95Codec() { @Override public KnnVectorsFormat getKnnVectorsFormatForField(String field) { - return new Lucene95HnswVectorsFormat(M, Lucene95HnswVectorsFormat.DEFAULT_BEAM_WIDTH); + return new Lucene95HnswVectorsFormat(M, HnswGraphBuilder.DEFAULT_BEAM_WIDTH); } }; @@ -92,7 +93,7 @@ public KnnVectorsFormat getKnnVectorsFormatForField(String field) { new Lucene95Codec() { @Override public KnnVectorsFormat getKnnVectorsFormatForField(String field) { - return new Lucene95HnswVectorsFormat(M, Lucene95HnswVectorsFormat.DEFAULT_BEAM_WIDTH); + return new Lucene95HnswVectorsFormat(M, HnswGraphBuilder.DEFAULT_BEAM_WIDTH); } }; @@ -103,7 +104,7 @@ public KnnVectorsFormat getKnnVectorsFormatForField(String field) { new Lucene95Codec() { @Override public KnnVectorsFormat getKnnVectorsFormatForField(String field) { - return new Lucene95HnswVectorsFormat(M, Lucene95HnswVectorsFormat.DEFAULT_BEAM_WIDTH); + return new Lucene95HnswVectorsFormat(M, HnswGraphBuilder.DEFAULT_BEAM_WIDTH); } }; } @@ -115,7 +116,7 @@ private VectorEncoding randomVectorEncoding() { @After public void cleanup() { - M = Lucene95HnswVectorsFormat.DEFAULT_MAX_CONN; + M = HnswGraphBuilder.DEFAULT_MAX_CONN; } /** Basic test of creating documents in a graph */ diff --git a/lucene/core/src/test/org/apache/lucene/search/BaseKnnVectorQueryTestCase.java b/lucene/core/src/test/org/apache/lucene/search/BaseKnnVectorQueryTestCase.java index ce1fa6d7abbe..24de1a463c73 100644 --- a/lucene/core/src/test/org/apache/lucene/search/BaseKnnVectorQueryTestCase.java +++ b/lucene/core/src/test/org/apache/lucene/search/BaseKnnVectorQueryTestCase.java @@ -210,7 +210,10 @@ public void testDimensionMismatch() throws IOException { IndexSearcher searcher = newSearcher(reader); AbstractKnnVectorQuery kvq = getKnnVectorQuery("field", new float[] {0}, 10); IllegalArgumentException e = - expectThrows(IllegalArgumentException.class, () -> searcher.search(kvq, 10)); + expectThrows( + RuntimeException.class, + IllegalArgumentException.class, + () -> searcher.search(kvq, 10)); assertEquals("vector query dimension: 1 differs from field dimension: 2", e.getMessage()); } } @@ -236,7 +239,7 @@ public void testDifferentReader() throws IOException { getIndexStore("field", new float[] {0, 1}, new float[] {1, 2}, new float[] {0, 0}); IndexReader reader = DirectoryReader.open(indexStore)) { AbstractKnnVectorQuery query = getKnnVectorQuery("field", new float[] {2, 3}, 3); - Query dasq = query.rewrite(reader); + Query dasq = query.rewrite(newSearcher(reader)); IndexSearcher leafSearcher = newSearcher(reader.leaves().get(0).reader()); expectThrows( IllegalStateException.class, @@ -256,7 +259,7 @@ public void testAdvanceShallow() throws IOException { try (IndexReader reader = DirectoryReader.open(d)) { IndexSearcher searcher = new IndexSearcher(reader); AbstractKnnVectorQuery query = getKnnVectorQuery("field", new float[] {2, 3}, 3); - Query dasq = query.rewrite(reader); + Query dasq = query.rewrite(searcher); Scorer scorer = dasq.createWeight(searcher, ScoreMode.COMPLETE, 1).scorer(reader.leaves().get(0)); // before advancing the iterator @@ -283,7 +286,7 @@ public void testScoreEuclidean() throws IOException { IndexReader reader = DirectoryReader.open(d)) { IndexSearcher searcher = new IndexSearcher(reader); AbstractKnnVectorQuery query = getKnnVectorQuery("field", new float[] {2, 3}, 3); - Query rewritten = query.rewrite(reader); + Query rewritten = query.rewrite(searcher); Weight weight = searcher.createWeight(rewritten, ScoreMode.COMPLETE, 1); Scorer scorer = weight.scorer(reader.leaves().get(0)); @@ -322,7 +325,7 @@ public void testScoreCosine() throws IOException { assertEquals(1, reader.leaves().size()); IndexSearcher searcher = new IndexSearcher(reader); AbstractKnnVectorQuery query = getKnnVectorQuery("field", new float[] {2, 3}, 3); - Query rewritten = query.rewrite(reader); + Query rewritten = query.rewrite(searcher); Weight weight = searcher.createWeight(rewritten, ScoreMode.COMPLETE, 1); Scorer scorer = weight.scorer(reader.leaves().get(0)); @@ -529,6 +532,7 @@ public void testRandomWithFilter() throws IOException { assertEquals(9, results.totalHits.value); assertEquals(results.totalHits.value, results.scoreDocs.length); expectThrows( + RuntimeException.class, UnsupportedOperationException.class, () -> searcher.search( @@ -543,6 +547,7 @@ public void testRandomWithFilter() throws IOException { assertEquals(5, results.totalHits.value); assertEquals(results.totalHits.value, results.scoreDocs.length); expectThrows( + RuntimeException.class, UnsupportedOperationException.class, () -> searcher.search( @@ -570,6 +575,7 @@ public void testRandomWithFilter() throws IOException { // Test a filter that exhausts visitedLimit in upper levels, and switches to exact search Query filter4 = IntPoint.newRangeQuery("tag", lower, lower + 2); expectThrows( + RuntimeException.class, UnsupportedOperationException.class, () -> searcher.search( @@ -742,6 +748,7 @@ public void testBitSetQuery() throws IOException { Query filter = new ThrowingBitSetQuery(new FixedBitSet(numDocs)); expectThrows( + RuntimeException.class, UnsupportedOperationException.class, () -> searcher.search( diff --git a/lucene/core/src/test/org/apache/lucene/search/TestBooleanRewrites.java b/lucene/core/src/test/org/apache/lucene/search/TestBooleanRewrites.java index 74badd25e777..87b8068d2f1f 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestBooleanRewrites.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestBooleanRewrites.java @@ -83,7 +83,7 @@ public void testSingleFilterClause() throws IOException { query1.add(new TermQuery(new Term("field", "a")), Occur.FILTER); // Single clauses rewrite to a term query - final Query rewritten1 = query1.build().rewrite(reader); + final Query rewritten1 = query1.build().rewrite(searcher); assertTrue(rewritten1 instanceof BoostQuery); assertEquals(0f, ((BoostQuery) rewritten1).getBoost(), 0f); @@ -946,7 +946,7 @@ public String toString(String field) { } @Override - public Query rewrite(IndexReader indexReader) { + public Query rewrite(IndexSearcher indexSearcher) { numRewrites++; return this; } diff --git a/lucene/core/src/test/org/apache/lucene/search/TestFieldExistsQuery.java b/lucene/core/src/test/org/apache/lucene/search/TestFieldExistsQuery.java index 307d6800aa57..209ad510889b 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestFieldExistsQuery.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestFieldExistsQuery.java @@ -63,7 +63,8 @@ public void testDocValuesRewriteWithTermsPresent() throws IOException { final IndexReader reader = iw.getReader(); iw.close(); - assertTrue((new FieldExistsQuery("f")).rewrite(reader) instanceof MatchAllDocsQuery); + assertTrue( + (new FieldExistsQuery("f")).rewrite(newSearcher(reader)) instanceof MatchAllDocsQuery); reader.close(); dir.close(); } @@ -82,7 +83,8 @@ public void testDocValuesRewriteWithPointValuesPresent() throws IOException { final IndexReader reader = iw.getReader(); iw.close(); - assertTrue(new FieldExistsQuery("dim").rewrite(reader) instanceof MatchAllDocsQuery); + assertTrue( + new FieldExistsQuery("dim").rewrite(newSearcher(reader)) instanceof MatchAllDocsQuery); reader.close(); dir.close(); } @@ -106,9 +108,10 @@ public void testDocValuesNoRewrite() throws IOException { iw.commit(); final IndexReader reader = iw.getReader(); iw.close(); + final IndexSearcher searcher = newSearcher(reader); - assertFalse((new FieldExistsQuery("dim")).rewrite(reader) instanceof MatchAllDocsQuery); - assertFalse((new FieldExistsQuery("f")).rewrite(reader) instanceof MatchAllDocsQuery); + assertFalse((new FieldExistsQuery("dim")).rewrite(searcher) instanceof MatchAllDocsQuery); + assertFalse((new FieldExistsQuery("f")).rewrite(searcher) instanceof MatchAllDocsQuery); reader.close(); dir.close(); } @@ -127,10 +130,11 @@ public void testDocValuesNoRewriteWithDocValues() throws IOException { iw.commit(); final IndexReader reader = iw.getReader(); iw.close(); + final IndexSearcher searcher = newSearcher(reader); - assertFalse((new FieldExistsQuery("dv1")).rewrite(reader) instanceof MatchAllDocsQuery); - assertFalse((new FieldExistsQuery("dv2")).rewrite(reader) instanceof MatchAllDocsQuery); - assertFalse((new FieldExistsQuery("dv3")).rewrite(reader) instanceof MatchAllDocsQuery); + assertFalse((new FieldExistsQuery("dv1")).rewrite(searcher) instanceof MatchAllDocsQuery); + assertFalse((new FieldExistsQuery("dv2")).rewrite(searcher) instanceof MatchAllDocsQuery); + assertFalse((new FieldExistsQuery("dv3")).rewrite(searcher) instanceof MatchAllDocsQuery); reader.close(); dir.close(); } diff --git a/lucene/core/src/test/org/apache/lucene/search/TestIndexSearcher.java b/lucene/core/src/test/org/apache/lucene/search/TestIndexSearcher.java index c3bcda9d47a6..7e8693bd8b31 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestIndexSearcher.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestIndexSearcher.java @@ -453,20 +453,15 @@ private void runSliceExecutorTest(ThreadPoolExecutor service, boolean useRandomS } } - private class RandomBlockingSliceExecutor extends SliceExecutor { + private static class RandomBlockingSliceExecutor extends SliceExecutor { - public RandomBlockingSliceExecutor(Executor executor) { + RandomBlockingSliceExecutor(Executor executor) { super(executor); } @Override - public void invokeAll(Collection tasks) { - - for (Runnable task : tasks) { - boolean shouldExecuteOnCallerThread = random().nextBoolean(); - - processTask(task, shouldExecuteOnCallerThread); - } + boolean shouldExecuteOnCallerThread(int index, int numTasks) { + return random().nextBoolean(); } } } diff --git a/lucene/core/src/test/org/apache/lucene/search/TestIndexSortSortedNumericDocValuesRangeQuery.java b/lucene/core/src/test/org/apache/lucene/search/TestIndexSortSortedNumericDocValuesRangeQuery.java index 8df8dcb1917e..cc5d8800e8a2 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestIndexSortSortedNumericDocValuesRangeQuery.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestIndexSortSortedNumericDocValuesRangeQuery.java @@ -339,7 +339,7 @@ public void testRewriteExhaustiveRange() throws IOException { IndexReader reader = writer.getReader(); Query query = createQuery("field", Long.MIN_VALUE, Long.MAX_VALUE); - Query rewrittenQuery = query.rewrite(reader); + Query rewrittenQuery = query.rewrite(newSearcher(reader)); assertEquals(new FieldExistsQuery("field"), rewrittenQuery); writer.close(); @@ -357,7 +357,7 @@ public void testRewriteFallbackQuery() throws IOException { Query fallbackQuery = new BooleanQuery.Builder().build(); Query query = new IndexSortSortedNumericDocValuesRangeQuery("field", 1, 42, fallbackQuery); - Query rewrittenQuery = query.rewrite(reader); + Query rewrittenQuery = query.rewrite(newSearcher(reader)); assertNotEquals(query, rewrittenQuery); assertThat(rewrittenQuery, instanceOf(IndexSortSortedNumericDocValuesRangeQuery.class)); diff --git a/lucene/core/src/test/org/apache/lucene/search/TestKnnFloatVectorQuery.java b/lucene/core/src/test/org/apache/lucene/search/TestKnnFloatVectorQuery.java index 684e260f12b7..8467ac506ae4 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestKnnFloatVectorQuery.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestKnnFloatVectorQuery.java @@ -95,7 +95,7 @@ public void testScoreNegativeDotProduct() throws IOException { assertEquals(1, reader.leaves().size()); IndexSearcher searcher = new IndexSearcher(reader); AbstractKnnVectorQuery query = getKnnVectorQuery("field", new float[] {1, 0}, 2); - Query rewritten = query.rewrite(reader); + Query rewritten = query.rewrite(searcher); Weight weight = searcher.createWeight(rewritten, ScoreMode.COMPLETE, 1); Scorer scorer = weight.scorer(reader.leaves().get(0)); @@ -126,7 +126,7 @@ public void testScoreDotProduct() throws IOException { IndexSearcher searcher = new IndexSearcher(reader); AbstractKnnVectorQuery query = getKnnVectorQuery("field", VectorUtil.l2normalize(new float[] {2, 3}), 3); - Query rewritten = query.rewrite(reader); + Query rewritten = query.rewrite(searcher); Weight weight = searcher.createWeight(rewritten, ScoreMode.COMPLETE, 1); Scorer scorer = weight.scorer(reader.leaves().get(0)); diff --git a/lucene/core/src/test/org/apache/lucene/search/TestMatchNoDocsQuery.java b/lucene/core/src/test/org/apache/lucene/search/TestMatchNoDocsQuery.java index e1facc81e61a..43db42cc1d34 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestMatchNoDocsQuery.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestMatchNoDocsQuery.java @@ -44,7 +44,7 @@ public void testSimple() throws Exception { assertEquals(query.toString(), "MatchNoDocsQuery(\"\")"); query = new MatchNoDocsQuery("field 'title' not found"); assertEquals(query.toString(), "MatchNoDocsQuery(\"field 'title' not found\")"); - Query rewrite = query.rewrite(null); + Query rewrite = query.rewrite((IndexSearcher) null); assertTrue(rewrite instanceof MatchNoDocsQuery); assertEquals(rewrite.toString(), "MatchNoDocsQuery(\"field 'title' not found\")"); } @@ -87,7 +87,7 @@ public void testQuery() throws Exception { assertEquals(query.toString(), "key:one MatchNoDocsQuery(\"field not found\")"); assertEquals(searcher.count(query), 1); hits = searcher.search(query, 1000).scoreDocs; - Query rewrite = query.rewrite(ir); + Query rewrite = query.rewrite(searcher); assertEquals(1, hits.length); assertEquals(rewrite.toString(), "key:one"); diff --git a/lucene/core/src/test/org/apache/lucene/search/TestMatchesIterator.java b/lucene/core/src/test/org/apache/lucene/search/TestMatchesIterator.java index b62d1ec69f15..33acb57c8a5d 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestMatchesIterator.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestMatchesIterator.java @@ -499,7 +499,7 @@ public void testMinimalSeekingWithWildcards() throws IOException { SeekCountingLeafReader reader = new SeekCountingLeafReader(getOnlyLeafReader(this.reader)); this.searcher = new IndexSearcher(reader); Query query = new PrefixQuery(new Term(FIELD_WITH_OFFSETS, "w")); - Weight w = searcher.createWeight(query.rewrite(reader), ScoreMode.COMPLETE, 1); + Weight w = searcher.createWeight(query.rewrite(searcher), ScoreMode.COMPLETE, 1); // docs 0-3 match several different terms here, but we only seek to the first term and // then short-cut return; other terms are ignored until we try and iterate over matches diff --git a/lucene/core/src/test/org/apache/lucene/search/TestNGramPhraseQuery.java b/lucene/core/src/test/org/apache/lucene/search/TestNGramPhraseQuery.java index f42a576ce54f..905b43b93ed1 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestNGramPhraseQuery.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestNGramPhraseQuery.java @@ -29,6 +29,7 @@ public class TestNGramPhraseQuery extends LuceneTestCase { private static IndexReader reader; private static Directory directory; + private static IndexSearcher searcher; @BeforeClass public static void beforeClass() throws Exception { @@ -36,6 +37,7 @@ public static void beforeClass() throws Exception { RandomIndexWriter writer = new RandomIndexWriter(random(), directory); writer.close(); reader = DirectoryReader.open(directory); + searcher = new IndexSearcher(reader); } @AfterClass @@ -50,8 +52,8 @@ public void testRewrite() throws Exception { // bi-gram test ABC => AB/BC => AB/BC NGramPhraseQuery pq1 = new NGramPhraseQuery(2, new PhraseQuery("f", "AB", "BC")); - Query q = pq1.rewrite(reader); - assertSame(q.rewrite(reader), q); + Query q = pq1.rewrite(searcher); + assertSame(q.rewrite(searcher), q); PhraseQuery rewritten1 = (PhraseQuery) q; assertArrayEquals(new Term[] {new Term("f", "AB"), new Term("f", "BC")}, rewritten1.getTerms()); assertArrayEquals(new int[] {0, 1}, rewritten1.getPositions()); @@ -59,7 +61,7 @@ public void testRewrite() throws Exception { // bi-gram test ABCD => AB/BC/CD => AB//CD NGramPhraseQuery pq2 = new NGramPhraseQuery(2, new PhraseQuery("f", "AB", "BC", "CD")); - q = pq2.rewrite(reader); + q = pq2.rewrite(searcher); assertTrue(q instanceof PhraseQuery); assertNotSame(pq2, q); PhraseQuery rewritten2 = (PhraseQuery) q; @@ -70,7 +72,7 @@ public void testRewrite() throws Exception { NGramPhraseQuery pq3 = new NGramPhraseQuery(3, new PhraseQuery("f", "ABC", "BCD", "CDE", "DEF", "EFG", "FGH")); - q = pq3.rewrite(reader); + q = pq3.rewrite(searcher); assertTrue(q instanceof PhraseQuery); assertNotSame(pq3, q); PhraseQuery rewritten3 = (PhraseQuery) q; diff --git a/lucene/core/src/test/org/apache/lucene/search/TestNeedsScores.java b/lucene/core/src/test/org/apache/lucene/search/TestNeedsScores.java index aa2f3c892122..03b585710868 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestNeedsScores.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestNeedsScores.java @@ -139,10 +139,10 @@ public Scorer scorer(LeafReaderContext context) throws IOException { } @Override - public Query rewrite(IndexReader reader) throws IOException { - Query in2 = in.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + Query in2 = in.rewrite(indexSearcher); if (in2 == in) { - return super.rewrite(reader); + return super.rewrite(indexSearcher); } else { return new AssertNeedsScores(in2, value); } diff --git a/lucene/core/src/test/org/apache/lucene/search/TestPhraseQuery.java b/lucene/core/src/test/org/apache/lucene/search/TestPhraseQuery.java index da93b3a19510..f721f5e4fe21 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestPhraseQuery.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestPhraseQuery.java @@ -567,7 +567,7 @@ public void testEmptyPhraseQuery() throws Throwable { /* test that a single term is rewritten to a term query */ public void testRewrite() throws IOException { PhraseQuery pq = new PhraseQuery("foo", "bar"); - Query rewritten = pq.rewrite(searcher.getIndexReader()); + Query rewritten = pq.rewrite(searcher); assertTrue(rewritten instanceof TermQuery); } diff --git a/lucene/core/src/test/org/apache/lucene/search/TestQueryRewriteBackwardsCompatibility.java b/lucene/core/src/test/org/apache/lucene/search/TestQueryRewriteBackwardsCompatibility.java new file mode 100644 index 000000000000..a9534b7f191e --- /dev/null +++ b/lucene/core/src/test/org/apache/lucene/search/TestQueryRewriteBackwardsCompatibility.java @@ -0,0 +1,269 @@ +/* + * 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.search; + +import java.io.IOException; +import java.util.Objects; +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.store.Directory; +import org.apache.lucene.tests.index.RandomIndexWriter; +import org.apache.lucene.tests.util.LuceneTestCase; + +public class TestQueryRewriteBackwardsCompatibility extends LuceneTestCase { + + public void testQueryRewriteNoOverrides() throws IOException { + Directory directory = newDirectory(); + RandomIndexWriter w = new RandomIndexWriter(random(), directory, newIndexWriterConfig()); + IndexReader reader = w.getReader(); + w.close(); + IndexSearcher searcher = newSearcher(reader); + Query queryNoOverrides = new TestQueryNoOverrides(); + assertSame(queryNoOverrides, searcher.rewrite(queryNoOverrides)); + assertSame(queryNoOverrides, queryNoOverrides.rewrite(searcher)); + assertSame(queryNoOverrides, queryNoOverrides.rewrite(reader)); + reader.close(); + directory.close(); + } + + public void testSingleQueryRewrite() throws IOException { + Directory directory = newDirectory(); + RandomIndexWriter w = new RandomIndexWriter(random(), directory, newIndexWriterConfig()); + IndexReader reader = w.getReader(); + w.close(); + IndexSearcher searcher = newSearcher(reader); + + RewriteCountingQuery oldQuery = new OldQuery(null); + RewriteCountingQuery newQuery = new NewQuery(null); + + oldQuery.rewrite(searcher); + oldQuery.rewrite(reader); + + newQuery.rewrite(searcher); + newQuery.rewrite(reader); + + assertEquals(2, oldQuery.rewriteCount); + assertEquals(2, newQuery.rewriteCount); + reader.close(); + directory.close(); + } + + public void testNestedQueryRewrite() throws IOException { + Directory dir = newDirectory(); + RandomIndexWriter w = new RandomIndexWriter(random(), dir, newIndexWriterConfig()); + IndexReader reader = w.getReader(); + w.close(); + IndexSearcher searcher = newSearcher(reader); + + RewriteCountingQuery query = random().nextBoolean() ? new NewQuery(null) : new OldQuery(null); + + for (int i = 0; i < 5 + random().nextInt(5); i++) { + query = random().nextBoolean() ? new NewQuery(query) : new OldQuery(query); + } + + query.rewrite(searcher); + query.rewrite(reader); + + RewriteCountingQuery innerQuery = query; + while (innerQuery != null) { + assertEquals(2, innerQuery.rewriteCount); + innerQuery = innerQuery.getInnerQuery(); + } + reader.close(); + dir.close(); + } + + public void testRewriteQueryInheritance() throws IOException { + Directory directory = newDirectory(); + RandomIndexWriter w = new RandomIndexWriter(random(), directory, newIndexWriterConfig()); + IndexReader reader = w.getReader(); + w.close(); + IndexSearcher searcher = newSearcher(reader); + NewRewritableCallingSuper oneRewrite = new NewRewritableCallingSuper(); + NewRewritableCallingSuper twoRewrites = new OldNewRewritableCallingSuper(); + NewRewritableCallingSuper threeRewrites = new OldOldNewRewritableCallingSuper(); + + searcher.rewrite(oneRewrite); + searcher.rewrite(twoRewrites); + searcher.rewrite(threeRewrites); + assertEquals(1, oneRewrite.rewriteCount); + assertEquals(2, twoRewrites.rewriteCount); + assertEquals(3, threeRewrites.rewriteCount); + + reader.close(); + directory.close(); + } + + private static class NewRewritableCallingSuper extends RewriteCountingQuery { + + @Override + public Query rewrite(IndexSearcher searcher) throws IOException { + rewriteCount++; + return super.rewrite(searcher); + } + + @Override + public String toString(String field) { + return "NewRewritableCallingSuper"; + } + + @Override + public void visit(QueryVisitor visitor) {} + + @Override + public boolean equals(Object obj) { + return obj instanceof NewRewritableCallingSuper; + } + + @Override + public int hashCode() { + return 1; + } + + @Override + RewriteCountingQuery getInnerQuery() { + return null; + } + } + + private static class OldNewRewritableCallingSuper extends NewRewritableCallingSuper { + @Override + public Query rewrite(IndexReader reader) throws IOException { + rewriteCount++; + return super.rewrite(reader); + } + } + + private static class OldOldNewRewritableCallingSuper extends OldNewRewritableCallingSuper { + @Override + public Query rewrite(IndexReader reader) throws IOException { + rewriteCount++; + return super.rewrite(reader); + } + } + + private abstract static class RewriteCountingQuery extends Query { + int rewriteCount = 0; + + abstract RewriteCountingQuery getInnerQuery(); + } + + private static class OldQuery extends RewriteCountingQuery { + private final RewriteCountingQuery optionalSubQuery; + + private OldQuery(RewriteCountingQuery optionalSubQuery) { + this.optionalSubQuery = optionalSubQuery; + } + + @Override + public Query rewrite(IndexReader reader) throws IOException { + if (this.optionalSubQuery != null) { + this.optionalSubQuery.rewrite(reader); + } + rewriteCount++; + return this; + } + + @Override + public String toString(String field) { + return "OldQuery"; + } + + @Override + public void visit(QueryVisitor visitor) {} + + @Override + public boolean equals(Object obj) { + return obj instanceof OldQuery + && Objects.equals(((OldQuery) obj).optionalSubQuery, optionalSubQuery); + } + + @Override + public int hashCode() { + return 42 ^ Objects.hash(optionalSubQuery); + } + + @Override + RewriteCountingQuery getInnerQuery() { + return optionalSubQuery; + } + } + + private static class NewQuery extends RewriteCountingQuery { + private final RewriteCountingQuery optionalSubQuery; + + private NewQuery(RewriteCountingQuery optionalSubQuery) { + this.optionalSubQuery = optionalSubQuery; + } + + @Override + public Query rewrite(IndexSearcher searcher) throws IOException { + if (this.optionalSubQuery != null) { + this.optionalSubQuery.rewrite(searcher); + } + rewriteCount++; + return this; + } + + @Override + public String toString(String field) { + return "NewQuery"; + } + + @Override + public void visit(QueryVisitor visitor) {} + + @Override + public boolean equals(Object obj) { + return obj instanceof NewQuery + && Objects.equals(((NewQuery) obj).optionalSubQuery, optionalSubQuery); + } + + @Override + public int hashCode() { + return 73 ^ Objects.hash(optionalSubQuery); + } + + @Override + RewriteCountingQuery getInnerQuery() { + return optionalSubQuery; + } + } + + private static class TestQueryNoOverrides extends Query { + + private final int randomHash = random().nextInt(); + + @Override + public String toString(String field) { + return "TestQueryNoOverrides"; + } + + @Override + public void visit(QueryVisitor visitor) {} + + @Override + public boolean equals(Object obj) { + return obj instanceof TestQueryNoOverrides + && randomHash == ((TestQueryNoOverrides) obj).randomHash; + } + + @Override + public int hashCode() { + return randomHash; + } + } +} diff --git a/lucene/core/src/test/org/apache/lucene/search/TestSynonymQuery.java b/lucene/core/src/test/org/apache/lucene/search/TestSynonymQuery.java index 123307e75f8e..ae026a87367f 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestSynonymQuery.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestSynonymQuery.java @@ -73,6 +73,18 @@ public void testEquals() { .addTerm(new Term("field", "c"), 0.2f) .addTerm(new Term("field", "d")) .build()); + + QueryUtils.checkUnequal( + new SynonymQuery.Builder("field").addTerm(new Term("field", "a"), 0.4f).build(), + new SynonymQuery.Builder("field").addTerm(new Term("field", "b"), 0.4f).build()); + + QueryUtils.checkUnequal( + new SynonymQuery.Builder("field").addTerm(new Term("field", "a"), 0.2f).build(), + new SynonymQuery.Builder("field").addTerm(new Term("field", "a"), 0.4f).build()); + + QueryUtils.checkUnequal( + new SynonymQuery.Builder("field1").addTerm(new Term("field1", "b"), 0.4f).build(), + new SynonymQuery.Builder("field2").addTerm(new Term("field2", "b"), 0.4f).build()); } public void testBogusParams() { @@ -127,6 +139,12 @@ public void testBogusParams() { () -> { new SynonymQuery.Builder("field1").addTerm(new Term("field1", "a"), -0f); }); + + expectThrows( + NullPointerException.class, + () -> new SynonymQuery.Builder(null).addTerm(new Term("field1", "a"), -0f)); + + expectThrows(NullPointerException.class, () -> new SynonymQuery.Builder(null).build()); } public void testToString() { diff --git a/lucene/core/src/test/org/apache/lucene/search/TestWANDScorer.java b/lucene/core/src/test/org/apache/lucene/search/TestWANDScorer.java index 936ae8f5834a..abc6d7138f36 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestWANDScorer.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestWANDScorer.java @@ -950,12 +950,12 @@ public int hashCode() { } @Override - public Query rewrite(IndexReader reader) throws IOException { - Query rewritten = query.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + Query rewritten = query.rewrite(indexSearcher); if (rewritten != query) { return new MaxScoreWrapperQuery(rewritten, maxRange, maxScore); } - return super.rewrite(reader); + return super.rewrite(indexSearcher); } @Override diff --git a/lucene/core/src/test/org/apache/lucene/store/TestBufferedIndexInput.java b/lucene/core/src/test/org/apache/lucene/store/TestBufferedIndexInput.java index 546a22493975..d19b2058e07b 100644 --- a/lucene/core/src/test/org/apache/lucene/store/TestBufferedIndexInput.java +++ b/lucene/core/src/test/org/apache/lucene/store/TestBufferedIndexInput.java @@ -18,6 +18,7 @@ import java.io.IOException; import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.util.Random; import org.apache.lucene.tests.util.LuceneTestCase; import org.apache.lucene.util.ArrayUtil; @@ -142,6 +143,72 @@ public void testEOF() throws Exception { }); } + // Test that when reading backwards, we page backwards rather than refilling + // on every call + public void testBackwardsByteReads() throws IOException { + MyBufferedIndexInput input = new MyBufferedIndexInput(1024 * 8); + for (int i = 2048; i > 0; i -= random().nextInt(16)) { + assertEquals(byten(i), input.readByte(i)); + } + assertEquals(3, input.readCount); + } + + public void testBackwardsShortReads() throws IOException { + MyBufferedIndexInput input = new MyBufferedIndexInput(1024 * 8); + ByteBuffer bb = ByteBuffer.allocate(2); + bb.order(ByteOrder.LITTLE_ENDIAN); + for (int i = 2048; i > 0; i -= (random().nextInt(16) + 1)) { + bb.clear(); + bb.put(byten(i)); + bb.put(byten(i + 1)); + assertEquals(bb.getShort(0), input.readShort(i)); + } + // readCount can be three or four, depending on whether or not we had to adjust the bufferStart + // to include a whole short + assertTrue( + "Expected 4 or 3, got " + input.readCount, input.readCount == 4 || input.readCount == 3); + } + + public void testBackwardsIntReads() throws IOException { + MyBufferedIndexInput input = new MyBufferedIndexInput(1024 * 8); + ByteBuffer bb = ByteBuffer.allocate(4); + bb.order(ByteOrder.LITTLE_ENDIAN); + for (int i = 2048; i > 0; i -= (random().nextInt(16) + 3)) { + bb.clear(); + bb.put(byten(i)); + bb.put(byten(i + 1)); + bb.put(byten(i + 2)); + bb.put(byten(i + 3)); + assertEquals(bb.getInt(0), input.readInt(i)); + } + // readCount can be three or four, depending on whether or not we had to adjust the bufferStart + // to include a whole int + assertTrue( + "Expected 4 or 3, got " + input.readCount, input.readCount == 4 || input.readCount == 3); + } + + public void testBackwardsLongReads() throws IOException { + MyBufferedIndexInput input = new MyBufferedIndexInput(1024 * 8); + ByteBuffer bb = ByteBuffer.allocate(8); + bb.order(ByteOrder.LITTLE_ENDIAN); + for (int i = 2048; i > 0; i -= (random().nextInt(16) + 7)) { + bb.clear(); + bb.put(byten(i)); + bb.put(byten(i + 1)); + bb.put(byten(i + 2)); + bb.put(byten(i + 3)); + bb.put(byten(i + 4)); + bb.put(byten(i + 5)); + bb.put(byten(i + 6)); + bb.put(byten(i + 7)); + assertEquals(bb.getLong(0), input.readLong(i)); + } + // readCount can be three or four, depending on whether or not we had to adjust the bufferStart + // to include a whole long + assertTrue( + "Expected 4 or 3, got " + input.readCount, input.readCount == 4 || input.readCount == 3); + } + // byten emulates a file - byten(n) returns the n'th byte in that file. // MyBufferedIndexInput reads this "file". private static byte byten(long n) { @@ -150,7 +217,8 @@ private static byte byten(long n) { private static class MyBufferedIndexInput extends BufferedIndexInput { private long pos; - private long len; + private final long len; + private long readCount = 0; public MyBufferedIndexInput(long len) { super("MyBufferedIndexInput(len=" + len + ")", BufferedIndexInput.BUFFER_SIZE); @@ -164,14 +232,15 @@ public MyBufferedIndexInput() { } @Override - protected void readInternal(ByteBuffer b) throws IOException { + protected void readInternal(ByteBuffer b) { + readCount++; while (b.hasRemaining()) { b.put(byten(pos++)); } } @Override - protected void seekInternal(long pos) throws IOException { + protected void seekInternal(long pos) { this.pos = pos; } diff --git a/lucene/core/src/test/org/apache/lucene/store/TestMmapDirectory.java b/lucene/core/src/test/org/apache/lucene/store/TestMmapDirectory.java index dc638f6a529e..5597161a3a98 100644 --- a/lucene/core/src/test/org/apache/lucene/store/TestMmapDirectory.java +++ b/lucene/core/src/test/org/apache/lucene/store/TestMmapDirectory.java @@ -48,9 +48,9 @@ private static boolean isMemorySegmentImpl() { public void testCorrectImplementation() { final int runtimeVersion = Runtime.version().feature(); - if (runtimeVersion == 19 || runtimeVersion == 20) { + if (runtimeVersion >= 19 && runtimeVersion <= 21) { assertTrue( - "on Java 19 and Java 20 we should use MemorySegmentIndexInputProvider to create mmap IndexInputs", + "on Java 19, 20, and 21 we should use MemorySegmentIndexInputProvider to create mmap IndexInputs", isMemorySegmentImpl()); } else { assertSame(MappedByteBufferIndexInputProvider.class, MMapDirectory.PROVIDER.getClass()); diff --git a/lucene/core/src/test/org/apache/lucene/util/TestUnicodeUtil.java b/lucene/core/src/test/org/apache/lucene/util/TestUnicodeUtil.java index 8e0348b706c6..2f309e945b74 100644 --- a/lucene/core/src/test/org/apache/lucene/util/TestUnicodeUtil.java +++ b/lucene/core/src/test/org/apache/lucene/util/TestUnicodeUtil.java @@ -166,6 +166,28 @@ public void testUTF8toUTF32() { } } + public void testUTF8CodePointAt() { + int num = atLeast(50000); + UnicodeUtil.UTF8CodePoint reuse = null; + for (int i = 0; i < num; i++) { + final String s = TestUtil.randomUnicodeString(random()); + final byte[] utf8 = new byte[UnicodeUtil.maxUTF8Length(s.length())]; + final int utf8Len = UnicodeUtil.UTF16toUTF8(s, 0, s.length(), utf8); + + int[] expected = s.codePoints().toArray(); + int pos = 0; + int expectedUpto = 0; + while (pos < utf8Len) { + reuse = UnicodeUtil.codePointAt(utf8, pos, reuse); + assertEquals(expected[expectedUpto], reuse.codePoint); + expectedUpto++; + pos += reuse.numBytes; + } + assertEquals(utf8Len, pos); + assertEquals(expected.length, expectedUpto); + } + } + public void testNewString() { final int[] codePoints = { Character.toCodePoint(Character.MIN_HIGH_SURROGATE, Character.MAX_LOW_SURROGATE), diff --git a/lucene/core/src/test/org/apache/lucene/util/TestVectorUtilProviders.java b/lucene/core/src/test/org/apache/lucene/util/TestVectorUtilProviders.java new file mode 100644 index 000000000000..be1205890bd8 --- /dev/null +++ b/lucene/core/src/test/org/apache/lucene/util/TestVectorUtilProviders.java @@ -0,0 +1,83 @@ +/* + * 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.util; + +import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import java.util.function.ToDoubleFunction; +import java.util.function.ToIntFunction; +import java.util.stream.IntStream; +import org.apache.lucene.tests.util.LuceneTestCase; +import org.junit.BeforeClass; + +public class TestVectorUtilProviders extends LuceneTestCase { + + private static final double DELTA = 1e-3; + private static final VectorUtilProvider LUCENE_PROVIDER = new VectorUtilDefaultProvider(); + private static final VectorUtilProvider JDK_PROVIDER = VectorUtilProvider.lookup(true); + + private static final int[] VECTOR_SIZES = { + 1, 4, 6, 8, 13, 16, 25, 32, 64, 100, 128, 207, 256, 300, 512, 702, 1024 + }; + + private final int size; + + public TestVectorUtilProviders(int size) { + this.size = size; + } + + @ParametersFactory + public static Iterable parametersFactory() { + return () -> IntStream.of(VECTOR_SIZES).boxed().map(i -> new Object[] {i}).iterator(); + } + + @BeforeClass + public static void beforeClass() throws Exception { + assumeFalse( + "Test only works when JDK's vector incubator module is enabled.", + JDK_PROVIDER instanceof VectorUtilDefaultProvider); + } + + public void testFloatVectors() { + var a = new float[size]; + var b = new float[size]; + for (int i = 0; i < size; ++i) { + a[i] = random().nextFloat(); + b[i] = random().nextFloat(); + } + assertFloatReturningProviders(p -> p.dotProduct(a, b)); + assertFloatReturningProviders(p -> p.squareDistance(a, b)); + assertFloatReturningProviders(p -> p.cosine(a, b)); + } + + public void testBinaryVectors() { + var a = new byte[size]; + var b = new byte[size]; + random().nextBytes(a); + random().nextBytes(b); + assertIntReturningProviders(p -> p.dotProduct(a, b)); + assertIntReturningProviders(p -> p.squareDistance(a, b)); + assertFloatReturningProviders(p -> p.cosine(a, b)); + } + + private void assertFloatReturningProviders(ToDoubleFunction func) { + assertEquals(func.applyAsDouble(LUCENE_PROVIDER), func.applyAsDouble(JDK_PROVIDER), DELTA); + } + + private void assertIntReturningProviders(ToIntFunction func) { + assertEquals(func.applyAsInt(LUCENE_PROVIDER), func.applyAsInt(JDK_PROVIDER)); + } +} diff --git a/lucene/core/src/test/org/apache/lucene/util/automaton/TestCompiledAutomaton.java b/lucene/core/src/test/org/apache/lucene/util/automaton/TestCompiledAutomaton.java index 5d63b8051cd0..4640bea2dc2c 100644 --- a/lucene/core/src/test/org/apache/lucene/util/automaton/TestCompiledAutomaton.java +++ b/lucene/core/src/test/org/apache/lucene/util/automaton/TestCompiledAutomaton.java @@ -35,7 +35,7 @@ private CompiledAutomaton build(int determinizeWorkLimit, String... strings) { terms.add(new BytesRef(s)); } Collections.sort(terms); - final Automaton a = DaciukMihovAutomatonBuilder.build(terms); + final Automaton a = Automata.makeStringUnion(terms); return new CompiledAutomaton(a, true, false, determinizeWorkLimit, false); } diff --git a/lucene/core/src/test/org/apache/lucene/util/automaton/TestDaciukMihovAutomatonBuilder.java b/lucene/core/src/test/org/apache/lucene/util/automaton/TestDaciukMihovAutomatonBuilder.java index 4b31eda98c6d..d72e08f18e98 100644 --- a/lucene/core/src/test/org/apache/lucene/util/automaton/TestDaciukMihovAutomatonBuilder.java +++ b/lucene/core/src/test/org/apache/lucene/util/automaton/TestDaciukMihovAutomatonBuilder.java @@ -16,26 +16,185 @@ */ package org.apache.lucene.util.automaton; +import com.carrotsearch.randomizedtesting.RandomizedTest; +import com.carrotsearch.randomizedtesting.generators.RandomNumbers; +import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; import org.apache.lucene.tests.util.LuceneTestCase; +import org.apache.lucene.tests.util.TestUtil; import org.apache.lucene.util.ArrayUtil; import org.apache.lucene.util.BytesRef; +import org.apache.lucene.util.BytesRefBuilder; +import org.apache.lucene.util.BytesRefIterator; +import org.apache.lucene.util.IntsRef; +import org.apache.lucene.util.fst.Util; public class TestDaciukMihovAutomatonBuilder extends LuceneTestCase { - public void testLargeTerms() { + public void testBasic() throws Exception { + List terms = basicTerms(); + Collections.sort(terms); + + Automaton a = build(terms, false); + checkAutomaton(terms, a, false); + checkMinimized(a); + } + + public void testBasicBinary() throws Exception { + List terms = basicTerms(); + Collections.sort(terms); + + Automaton a = build(terms, true); + checkAutomaton(terms, a, true); + checkMinimized(a); + } + + public void testRandomMinimized() throws Exception { + int iters = RandomizedTest.isNightly() ? 20 : 5; + for (int i = 0; i < iters; i++) { + boolean buildBinary = random().nextBoolean(); + int size = RandomNumbers.randomIntBetween(random(), 2, 50); + Set terms = new HashSet<>(); + List automatonList = new ArrayList<>(size); + for (int j = 0; j < size; j++) { + if (buildBinary) { + BytesRef t = TestUtil.randomBinaryTerm(random(), 8); + terms.add(t); + automatonList.add(Automata.makeBinary(t)); + } else { + String s = TestUtil.randomRealisticUnicodeString(random(), 8); + terms.add(newBytesRef(s)); + automatonList.add(Automata.makeString(s)); + } + } + List sortedTerms = terms.stream().sorted().collect(Collectors.toList()); + + Automaton expected = + MinimizationOperations.minimize( + Operations.union(automatonList), Operations.DEFAULT_DETERMINIZE_WORK_LIMIT); + Automaton actual = build(sortedTerms, buildBinary); + assertSameAutomaton(expected, actual); + } + } + + public void testRandomUnicodeOnly() throws Exception { + testRandom(false); + } + + public void testRandomBinary() throws Exception { + testRandom(true); + } + + public void testLargeTerms() throws Exception { byte[] b10k = new byte[10_000]; Arrays.fill(b10k, (byte) 'a'); IllegalArgumentException e = expectThrows( IllegalArgumentException.class, - () -> DaciukMihovAutomatonBuilder.build(Collections.singleton(new BytesRef(b10k)))); + () -> build(Collections.singleton(new BytesRef(b10k)), false)); assertTrue( e.getMessage() - .startsWith("This builder doesn't allow terms that are larger than 1,000 characters")); + .startsWith( + "This builder doesn't allow terms that are larger than " + + Automata.MAX_STRING_UNION_TERM_LENGTH + + " characters")); byte[] b1k = ArrayUtil.copyOfSubArray(b10k, 0, 1000); - DaciukMihovAutomatonBuilder.build(Collections.singleton(new BytesRef(b1k))); // no exception + build(Collections.singleton(new BytesRef(b1k)), false); // no exception + } + + private void testRandom(boolean allowBinary) throws Exception { + int iters = RandomizedTest.isNightly() ? 50 : 10; + for (int i = 0; i < iters; i++) { + int size = RandomNumbers.randomIntBetween(random(), 500, 2_000); + Set terms = new HashSet<>(size); + for (int j = 0; j < size; j++) { + if (allowBinary && random().nextInt(10) < 2) { + // Sometimes random bytes term that isn't necessarily valid unicode + terms.add(newBytesRef(TestUtil.randomBinaryTerm(random()))); + } else { + terms.add(newBytesRef(TestUtil.randomRealisticUnicodeString(random()))); + } + } + + List sorted = terms.stream().sorted().collect(Collectors.toList()); + Automaton a = build(sorted, allowBinary); + checkAutomaton(sorted, a, allowBinary); + } + } + + private void checkAutomaton(List expected, Automaton a, boolean isBinary) { + CompiledAutomaton c = + new CompiledAutomaton(a, true, false, Operations.DEFAULT_DETERMINIZE_WORK_LIMIT, isBinary); + ByteRunAutomaton runAutomaton = c.runAutomaton; + + // Make sure every expected term is accepted + for (BytesRef t : expected) { + String readable = isBinary ? t.toString() : t.utf8ToString(); + assertTrue( + readable + " should be found but wasn't", runAutomaton.run(t.bytes, t.offset, t.length)); + } + + // Make sure every term produced by the automaton is expected + BytesRefBuilder scratch = new BytesRefBuilder(); + FiniteStringsIterator it = new FiniteStringsIterator(c.automaton); + for (IntsRef r = it.next(); r != null; r = it.next()) { + BytesRef t = Util.toBytesRef(r, scratch); + assertTrue(expected.contains(t)); + } + } + + private void checkMinimized(Automaton a) { + Automaton minimized = + MinimizationOperations.minimize(a, Operations.DEFAULT_DETERMINIZE_WORK_LIMIT); + assertSameAutomaton(minimized, a); + } + + private static void assertSameAutomaton(Automaton a, Automaton b) { + assertEquals(a.getNumStates(), b.getNumStates()); + assertEquals(a.getNumTransitions(), b.getNumTransitions()); + assertTrue(Operations.sameLanguage(a, b)); + } + + private List basicTerms() { + List terms = new ArrayList<>(); + terms.add(newBytesRef("dog")); + terms.add(newBytesRef("day")); + terms.add(newBytesRef("dad")); + terms.add(newBytesRef("cats")); + terms.add(newBytesRef("cat")); + return terms; + } + + private Automaton build(Collection terms, boolean asBinary) throws IOException { + if (random().nextBoolean()) { + return DaciukMihovAutomatonBuilder.build(terms, asBinary); + } else { + return DaciukMihovAutomatonBuilder.build(new TermIterator(terms), asBinary); + } + } + + private static final class TermIterator implements BytesRefIterator { + private final Iterator it; + + TermIterator(Collection terms) { + this.it = terms.iterator(); + } + + @Override + public BytesRef next() throws IOException { + if (it.hasNext() == false) { + return null; + } + return it.next(); + } } } diff --git a/lucene/core/src/test/org/apache/lucene/util/automaton/TestOperations.java b/lucene/core/src/test/org/apache/lucene/util/automaton/TestOperations.java index 62913c166598..b8ef5645438b 100644 --- a/lucene/core/src/test/org/apache/lucene/util/automaton/TestOperations.java +++ b/lucene/core/src/test/org/apache/lucene/util/automaton/TestOperations.java @@ -17,6 +17,7 @@ package org.apache.lucene.util.automaton; import static org.apache.lucene.util.automaton.Operations.DEFAULT_DETERMINIZE_WORK_LIMIT; +import static org.apache.lucene.util.automaton.Operations.topoSortStates; import com.carrotsearch.randomizedtesting.generators.RandomNumbers; import java.util.ArrayList; @@ -69,6 +70,42 @@ public void testEmptyLanguageConcatenate() { assertTrue(Operations.isEmpty(concat)); } + /** + * Test case for the topoSortStates method when the input Automaton contains a cycle. This test + * case constructs an Automaton with two disjoint sets of states—one without a cycle and one with + * a cycle. The topoSortStates method should detect the presence of a cycle and throw an + * IllegalArgumentException. + */ + public void testCycledAutomaton() { + Automaton a = generateRandomAutomaton(true); + IllegalArgumentException exc = + expectThrows(IllegalArgumentException.class, () -> topoSortStates(a)); + assertTrue(exc.getMessage().contains("Input automaton has a cycle")); + } + + public void testTopoSortStates() { + Automaton a = generateRandomAutomaton(false); + + int[] sorted = topoSortStates(a); + int[] stateMap = new int[a.getNumStates()]; + Arrays.fill(stateMap, -1); + int order = 0; + for (int state : sorted) { + assertEquals(-1, stateMap[state]); + stateMap[state] = (order++); + } + + Transition transition = new Transition(); + for (int state : sorted) { + int count = a.initTransition(state, transition); + for (int i = 0; i < count; i++) { + a.getNextTransition(transition); + // ensure dest's order is higher than current state + assertTrue(stateMap[transition.dest] > stateMap[state]); + } + } + } + /** Test optimization to concatenate() with empty String to an NFA */ public void testEmptySingletonNFAConcatenate() { Automaton singleton = Automata.makeString(""); @@ -144,19 +181,6 @@ public void testIsFiniteEatsStack() { assertTrue(exc.getMessage().contains("input automaton is too large")); } - public void testTopoSortEatsStack() { - char[] chars = new char[50000]; - TestUtil.randomFixedLengthUnicodeString(random(), chars, 0, chars.length); - String bigString1 = new String(chars); - TestUtil.randomFixedLengthUnicodeString(random(), chars, 0, chars.length); - String bigString2 = new String(chars); - Automaton a = - Operations.union(Automata.makeString(bigString1), Automata.makeString(bigString2)); - IllegalArgumentException exc = - expectThrows(IllegalArgumentException.class, () -> Operations.topoSortStates(a)); - assertTrue(exc.getMessage().contains("input automaton is too large")); - } - /** * Returns the set of all accepted strings. * @@ -190,4 +214,52 @@ private static Set getFiniteStrings(FiniteStringsIterator iterator) { return result; } + + /** + * This method creates a random Automaton by generating states at multiple levels. At each level, + * a random number of states are created, and transitions are added between the states of the + * current and the previous level randomly, If the 'hasCycle' parameter is true, a transition is + * added from the first state of the last level back to the initial state to create a cycle in the + * Automaton.. + * + * @param hasCycle if true, the generated Automaton will have a cycle; if false, it won't have a + * cycle. + * @return a randomly generated Automaton instance. + */ + private Automaton generateRandomAutomaton(boolean hasCycle) { + Automaton a = new Automaton(); + List lastLevelStates = new ArrayList<>(); + int initialState = a.createState(); + int maxLevel = TestUtil.nextInt(random(), 4, 9); + lastLevelStates.add(initialState); + + for (int level = 1; level < maxLevel; level++) { + int numStates = TestUtil.nextInt(random(), 3, 9); + List nextLevelStates = new ArrayList<>(); + + for (int i = 0; i < numStates; i++) { + int nextState = a.createState(); + nextLevelStates.add(nextState); + } + + for (int lastState : lastLevelStates) { + for (int nextState : nextLevelStates) { + // if hasCycle is enabled, we will always add a transition, so we could make sure the + // generated Automaton has a cycle. + if (hasCycle || random().nextInt(7) >= 1) { + a.addTransition(lastState, nextState, random().nextInt(10)); + } + } + } + lastLevelStates = nextLevelStates; + } + + if (hasCycle) { + int lastState = lastLevelStates.get(0); + a.addTransition(lastState, initialState, random().nextInt(10)); + } + + a.finishState(); + return a; + } } diff --git a/lucene/core/src/test/org/apache/lucene/util/graph/TestGraphTokenStreamFiniteStrings.java b/lucene/core/src/test/org/apache/lucene/util/graph/TestGraphTokenStreamFiniteStrings.java index e68b892d01ce..4df3a0eb029a 100644 --- a/lucene/core/src/test/org/apache/lucene/util/graph/TestGraphTokenStreamFiniteStrings.java +++ b/lucene/core/src/test/org/apache/lucene/util/graph/TestGraphTokenStreamFiniteStrings.java @@ -16,6 +16,7 @@ */ package org.apache.lucene.util.graph; +import java.util.ArrayList; import java.util.Iterator; import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; @@ -660,4 +661,27 @@ public void testMultipleSidePathsWithGaps() throws Exception { it.next(), new String[] {"king", "alfred", "saxons", "ruled"}, new int[] {1, 1, 3, 1}); assertFalse(it.hasNext()); } + + public void testLongTokenStreamStackOverflowError() throws Exception { + + ArrayList tokens = + new ArrayList() { + { + add(token("fast", 1, 1)); + add(token("wi", 1, 1)); + add(token("wifi", 0, 2)); + add(token("fi", 1, 1)); + } + }; + + // Add in too many tokens to get a high depth graph + for (int i = 0; i < 1024 + 1; i++) { + tokens.add(token("network", 1, 1)); + } + + TokenStream ts = new CannedTokenStream(tokens.toArray(new Token[0])); + GraphTokenStreamFiniteStrings graph = new GraphTokenStreamFiniteStrings(ts); + + assertThrows(IllegalArgumentException.class, graph::articulationPoints); + } } diff --git a/lucene/core/src/test/org/apache/lucene/util/hnsw/HnswGraphTestCase.java b/lucene/core/src/test/org/apache/lucene/util/hnsw/HnswGraphTestCase.java index 63aebc40dd75..a6ddb84f2da3 100644 --- a/lucene/core/src/test/org/apache/lucene/util/hnsw/HnswGraphTestCase.java +++ b/lucene/core/src/test/org/apache/lucene/util/hnsw/HnswGraphTestCase.java @@ -32,6 +32,12 @@ import java.util.Map; import java.util.Random; import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.stream.Collectors; import org.apache.lucene.codecs.KnnVectorsFormat; import org.apache.lucene.codecs.lucene95.Lucene95Codec; @@ -66,6 +72,7 @@ import org.apache.lucene.util.BitSet; import org.apache.lucene.util.Bits; import org.apache.lucene.util.FixedBitSet; +import org.apache.lucene.util.NamedThreadFactory; import org.apache.lucene.util.RamUsageEstimator; import org.apache.lucene.util.VectorUtil; import org.apache.lucene.util.hnsw.HnswGraph.NodesIterator; @@ -990,6 +997,115 @@ public void testRandom() throws IOException { assertTrue("overlap=" + overlap, overlap > 0.9); } + /* test thread-safety of searching OnHeapHnswGraph */ + @SuppressWarnings("unchecked") + public void testOnHeapHnswGraphSearch() + throws IOException, ExecutionException, InterruptedException, TimeoutException { + int size = atLeast(100); + int dim = atLeast(10); + AbstractMockVectorValues vectors = vectorValues(size, dim); + int topK = 5; + HnswGraphBuilder builder = + HnswGraphBuilder.create( + vectors, getVectorEncoding(), similarityFunction, 10, 30, random().nextLong()); + OnHeapHnswGraph hnsw = builder.build(vectors.copy()); + Bits acceptOrds = random().nextBoolean() ? null : createRandomAcceptOrds(0, size); + + List queries = new ArrayList<>(); + List expects = new ArrayList<>(); + for (int i = 0; i < 100; i++) { + NeighborQueue expect = null; + T query = randomVector(dim); + queries.add(query); + switch (getVectorEncoding()) { + case BYTE: + expect = + HnswGraphSearcher.search( + (byte[]) query, + 100, + (RandomAccessVectorValues) vectors, + getVectorEncoding(), + similarityFunction, + hnsw, + acceptOrds, + Integer.MAX_VALUE); + break; + case FLOAT32: + expect = + HnswGraphSearcher.search( + (float[]) query, + 100, + (RandomAccessVectorValues) vectors, + getVectorEncoding(), + similarityFunction, + hnsw, + acceptOrds, + Integer.MAX_VALUE); + } + ; + while (expect.size() > topK) { + expect.pop(); + } + expects.add(expect); + } + + ExecutorService exec = + Executors.newFixedThreadPool(4, new NamedThreadFactory("onHeapHnswSearch")); + List> futures = new ArrayList<>(); + for (T query : queries) { + futures.add( + exec.submit( + () -> { + NeighborQueue actual = null; + try { + + switch (getVectorEncoding()) { + case BYTE: + actual = + HnswGraphSearcher.search( + (byte[]) query, + 100, + (RandomAccessVectorValues) vectors, + getVectorEncoding(), + similarityFunction, + hnsw, + acceptOrds, + Integer.MAX_VALUE); + break; + case FLOAT32: + actual = + HnswGraphSearcher.search( + (float[]) query, + 100, + (RandomAccessVectorValues) vectors, + getVectorEncoding(), + similarityFunction, + hnsw, + acceptOrds, + Integer.MAX_VALUE); + } + ; + } catch (IOException ioe) { + throw new RuntimeException(ioe); + } + while (actual.size() > topK) { + actual.pop(); + } + return actual; + })); + } + List actuals = new ArrayList<>(); + for (Future future : futures) { + actuals.add(future.get(10, TimeUnit.SECONDS)); + } + exec.shutdownNow(); + for (int i = 0; i < expects.size(); i++) { + NeighborQueue expect = expects.get(i); + NeighborQueue actual = actuals.get(i); + assertArrayEquals(expect.nodes(), actual.nodes()); + } + } + private int computeOverlap(int[] a, int[] b) { Arrays.sort(a); Arrays.sort(b); diff --git a/lucene/core/src/test/org/apache/lucene/util/hnsw/TestNeighborArray.java b/lucene/core/src/test/org/apache/lucene/util/hnsw/TestNeighborArray.java index b8ae24f62009..c81077aa6daf 100644 --- a/lucene/core/src/test/org/apache/lucene/util/hnsw/TestNeighborArray.java +++ b/lucene/core/src/test/org/apache/lucene/util/hnsw/TestNeighborArray.java @@ -23,100 +23,160 @@ public class TestNeighborArray extends LuceneTestCase { public void testScoresDescOrder() { NeighborArray neighbors = new NeighborArray(10, true); - neighbors.add(0, 1); - neighbors.add(1, 0.8f); + neighbors.addInOrder(0, 1); + neighbors.addInOrder(1, 0.8f); - AssertionError ex = expectThrows(AssertionError.class, () -> neighbors.add(2, 0.9f)); - assertEquals("Nodes are added in the incorrect order!", ex.getMessage()); + AssertionError ex = expectThrows(AssertionError.class, () -> neighbors.addInOrder(2, 0.9f)); + assert ex.getMessage().startsWith("Nodes are added in the incorrect order!") : ex.getMessage(); neighbors.insertSorted(3, 0.9f); assertScoresEqual(new float[] {1, 0.9f, 0.8f}, neighbors); - asserNodesEqual(new int[] {0, 3, 1}, neighbors); + assertNodesEqual(new int[] {0, 3, 1}, neighbors); neighbors.insertSorted(4, 1f); assertScoresEqual(new float[] {1, 1, 0.9f, 0.8f}, neighbors); - asserNodesEqual(new int[] {0, 4, 3, 1}, neighbors); + assertNodesEqual(new int[] {0, 4, 3, 1}, neighbors); neighbors.insertSorted(5, 1.1f); assertScoresEqual(new float[] {1.1f, 1, 1, 0.9f, 0.8f}, neighbors); - asserNodesEqual(new int[] {5, 0, 4, 3, 1}, neighbors); + assertNodesEqual(new int[] {5, 0, 4, 3, 1}, neighbors); neighbors.insertSorted(6, 0.8f); assertScoresEqual(new float[] {1.1f, 1, 1, 0.9f, 0.8f, 0.8f}, neighbors); - asserNodesEqual(new int[] {5, 0, 4, 3, 1, 6}, neighbors); + assertNodesEqual(new int[] {5, 0, 4, 3, 1, 6}, neighbors); neighbors.insertSorted(7, 0.8f); assertScoresEqual(new float[] {1.1f, 1, 1, 0.9f, 0.8f, 0.8f, 0.8f}, neighbors); - asserNodesEqual(new int[] {5, 0, 4, 3, 1, 6, 7}, neighbors); + assertNodesEqual(new int[] {5, 0, 4, 3, 1, 6, 7}, neighbors); neighbors.removeIndex(2); assertScoresEqual(new float[] {1.1f, 1, 0.9f, 0.8f, 0.8f, 0.8f}, neighbors); - asserNodesEqual(new int[] {5, 0, 3, 1, 6, 7}, neighbors); + assertNodesEqual(new int[] {5, 0, 3, 1, 6, 7}, neighbors); neighbors.removeIndex(0); assertScoresEqual(new float[] {1, 0.9f, 0.8f, 0.8f, 0.8f}, neighbors); - asserNodesEqual(new int[] {0, 3, 1, 6, 7}, neighbors); + assertNodesEqual(new int[] {0, 3, 1, 6, 7}, neighbors); neighbors.removeIndex(4); assertScoresEqual(new float[] {1, 0.9f, 0.8f, 0.8f}, neighbors); - asserNodesEqual(new int[] {0, 3, 1, 6}, neighbors); + assertNodesEqual(new int[] {0, 3, 1, 6}, neighbors); neighbors.removeLast(); assertScoresEqual(new float[] {1, 0.9f, 0.8f}, neighbors); - asserNodesEqual(new int[] {0, 3, 1}, neighbors); + assertNodesEqual(new int[] {0, 3, 1}, neighbors); neighbors.insertSorted(8, 0.9f); assertScoresEqual(new float[] {1, 0.9f, 0.9f, 0.8f}, neighbors); - asserNodesEqual(new int[] {0, 3, 8, 1}, neighbors); + assertNodesEqual(new int[] {0, 3, 8, 1}, neighbors); } public void testScoresAscOrder() { NeighborArray neighbors = new NeighborArray(10, false); - neighbors.add(0, 0.1f); - neighbors.add(1, 0.3f); + neighbors.addInOrder(0, 0.1f); + neighbors.addInOrder(1, 0.3f); - AssertionError ex = expectThrows(AssertionError.class, () -> neighbors.add(2, 0.15f)); - assertEquals("Nodes are added in the incorrect order!", ex.getMessage()); + AssertionError ex = expectThrows(AssertionError.class, () -> neighbors.addInOrder(2, 0.15f)); + assert ex.getMessage().startsWith("Nodes are added in the incorrect order!") : ex.getMessage(); neighbors.insertSorted(3, 0.3f); assertScoresEqual(new float[] {0.1f, 0.3f, 0.3f}, neighbors); - asserNodesEqual(new int[] {0, 1, 3}, neighbors); + assertNodesEqual(new int[] {0, 1, 3}, neighbors); neighbors.insertSorted(4, 0.2f); assertScoresEqual(new float[] {0.1f, 0.2f, 0.3f, 0.3f}, neighbors); - asserNodesEqual(new int[] {0, 4, 1, 3}, neighbors); + assertNodesEqual(new int[] {0, 4, 1, 3}, neighbors); neighbors.insertSorted(5, 0.05f); assertScoresEqual(new float[] {0.05f, 0.1f, 0.2f, 0.3f, 0.3f}, neighbors); - asserNodesEqual(new int[] {5, 0, 4, 1, 3}, neighbors); + assertNodesEqual(new int[] {5, 0, 4, 1, 3}, neighbors); neighbors.insertSorted(6, 0.2f); assertScoresEqual(new float[] {0.05f, 0.1f, 0.2f, 0.2f, 0.3f, 0.3f}, neighbors); - asserNodesEqual(new int[] {5, 0, 4, 6, 1, 3}, neighbors); + assertNodesEqual(new int[] {5, 0, 4, 6, 1, 3}, neighbors); neighbors.insertSorted(7, 0.2f); assertScoresEqual(new float[] {0.05f, 0.1f, 0.2f, 0.2f, 0.2f, 0.3f, 0.3f}, neighbors); - asserNodesEqual(new int[] {5, 0, 4, 6, 7, 1, 3}, neighbors); + assertNodesEqual(new int[] {5, 0, 4, 6, 7, 1, 3}, neighbors); neighbors.removeIndex(2); assertScoresEqual(new float[] {0.05f, 0.1f, 0.2f, 0.2f, 0.3f, 0.3f}, neighbors); - asserNodesEqual(new int[] {5, 0, 6, 7, 1, 3}, neighbors); + assertNodesEqual(new int[] {5, 0, 6, 7, 1, 3}, neighbors); neighbors.removeIndex(0); assertScoresEqual(new float[] {0.1f, 0.2f, 0.2f, 0.3f, 0.3f}, neighbors); - asserNodesEqual(new int[] {0, 6, 7, 1, 3}, neighbors); + assertNodesEqual(new int[] {0, 6, 7, 1, 3}, neighbors); neighbors.removeIndex(4); assertScoresEqual(new float[] {0.1f, 0.2f, 0.2f, 0.3f}, neighbors); - asserNodesEqual(new int[] {0, 6, 7, 1}, neighbors); + assertNodesEqual(new int[] {0, 6, 7, 1}, neighbors); neighbors.removeLast(); assertScoresEqual(new float[] {0.1f, 0.2f, 0.2f}, neighbors); - asserNodesEqual(new int[] {0, 6, 7}, neighbors); + assertNodesEqual(new int[] {0, 6, 7}, neighbors); neighbors.insertSorted(8, 0.01f); assertScoresEqual(new float[] {0.01f, 0.1f, 0.2f, 0.2f}, neighbors); - asserNodesEqual(new int[] {8, 0, 6, 7}, neighbors); + assertNodesEqual(new int[] {8, 0, 6, 7}, neighbors); + } + + public void testSortAsc() { + NeighborArray neighbors = new NeighborArray(10, false); + neighbors.addOutOfOrder(1, 2); + // we disallow calling addInOrder after addOutOfOrder even if they're actual in order + expectThrows(AssertionError.class, () -> neighbors.addInOrder(1, 2)); + neighbors.addOutOfOrder(2, 3); + neighbors.addOutOfOrder(5, 6); + neighbors.addOutOfOrder(3, 4); + neighbors.addOutOfOrder(7, 8); + neighbors.addOutOfOrder(6, 7); + neighbors.addOutOfOrder(4, 5); + int[] unchecked = neighbors.sort(); + assertArrayEquals(new int[] {0, 1, 2, 3, 4, 5, 6}, unchecked); + assertNodesEqual(new int[] {1, 2, 3, 4, 5, 6, 7}, neighbors); + assertScoresEqual(new float[] {2, 3, 4, 5, 6, 7, 8}, neighbors); + + NeighborArray neighbors2 = new NeighborArray(10, false); + neighbors2.addInOrder(0, 1); + neighbors2.addInOrder(1, 2); + neighbors2.addInOrder(4, 5); + neighbors2.addOutOfOrder(2, 3); + neighbors2.addOutOfOrder(6, 7); + neighbors2.addOutOfOrder(5, 6); + neighbors2.addOutOfOrder(3, 4); + unchecked = neighbors2.sort(); + assertArrayEquals(new int[] {2, 3, 5, 6}, unchecked); + assertNodesEqual(new int[] {0, 1, 2, 3, 4, 5, 6}, neighbors2); + assertScoresEqual(new float[] {1, 2, 3, 4, 5, 6, 7}, neighbors2); + } + + public void testSortDesc() { + NeighborArray neighbors = new NeighborArray(10, true); + neighbors.addOutOfOrder(1, 7); + // we disallow calling addInOrder after addOutOfOrder even if they're actual in order + expectThrows(AssertionError.class, () -> neighbors.addInOrder(1, 2)); + neighbors.addOutOfOrder(2, 6); + neighbors.addOutOfOrder(5, 3); + neighbors.addOutOfOrder(3, 5); + neighbors.addOutOfOrder(7, 1); + neighbors.addOutOfOrder(6, 2); + neighbors.addOutOfOrder(4, 4); + int[] unchecked = neighbors.sort(); + assertArrayEquals(new int[] {0, 1, 2, 3, 4, 5, 6}, unchecked); + assertNodesEqual(new int[] {1, 2, 3, 4, 5, 6, 7}, neighbors); + assertScoresEqual(new float[] {7, 6, 5, 4, 3, 2, 1}, neighbors); + + NeighborArray neighbors2 = new NeighborArray(10, true); + neighbors2.addInOrder(1, 7); + neighbors2.addInOrder(2, 6); + neighbors2.addInOrder(5, 3); + neighbors2.addOutOfOrder(3, 5); + neighbors2.addOutOfOrder(7, 1); + neighbors2.addOutOfOrder(6, 2); + neighbors2.addOutOfOrder(4, 4); + unchecked = neighbors2.sort(); + assertArrayEquals(new int[] {2, 3, 5, 6}, unchecked); + assertNodesEqual(new int[] {1, 2, 3, 4, 5, 6, 7}, neighbors2); + assertScoresEqual(new float[] {7, 6, 5, 4, 3, 2, 1}, neighbors2); } private void assertScoresEqual(float[] scores, NeighborArray neighbors) { @@ -125,7 +185,7 @@ private void assertScoresEqual(float[] scores, NeighborArray neighbors) { } } - private void asserNodesEqual(int[] nodes, NeighborArray neighbors) { + private void assertNodesEqual(int[] nodes, NeighborArray neighbors) { for (int i = 0; i < nodes.length; i++) { assertEquals(nodes[i], neighbors.node[i]); } diff --git a/lucene/distribution.tests/src/test/org/apache/lucene/distribution/TestModularLayer.java b/lucene/distribution.tests/src/test/org/apache/lucene/distribution/TestModularLayer.java index b3e55f277706..a5b8f6409e93 100644 --- a/lucene/distribution.tests/src/test/org/apache/lucene/distribution/TestModularLayer.java +++ b/lucene/distribution.tests/src/test/org/apache/lucene/distribution/TestModularLayer.java @@ -206,7 +206,7 @@ public void testMultiReleaseJar() { ClassLoader loader = layer.findLoader(coreModuleId); - final Set jarVersions = Set.of(19, 20); + final Set jarVersions = Set.of(19, 20, 21); for (var v : jarVersions) { Assertions.assertThat( loader.getResource( diff --git a/lucene/facet/src/java/org/apache/lucene/facet/DrillDownQuery.java b/lucene/facet/src/java/org/apache/lucene/facet/DrillDownQuery.java index a4d47aa8c129..9fe4b15b9072 100644 --- a/lucene/facet/src/java/org/apache/lucene/facet/DrillDownQuery.java +++ b/lucene/facet/src/java/org/apache/lucene/facet/DrillDownQuery.java @@ -24,11 +24,11 @@ import java.util.Map; import java.util.Objects; import java.util.Set; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.Term; import org.apache.lucene.search.BooleanClause.Occur; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.BoostQuery; +import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.QueryVisitor; @@ -100,8 +100,8 @@ public DrillDownQuery(FacetsConfig config) { /** * Creates a new {@code DrillDownQuery} over the given base query. Can be {@code null}, in which - * case the result {@link Query} from {@link #rewrite(IndexReader)} will be a pure browsing query, - * filtering on the added categories only. + * case the result {@link Query} from {@link Query#rewrite(IndexSearcher)} will be a pure browsing + * query, filtering on the added categories only. */ public DrillDownQuery(FacetsConfig config, Query baseQuery) { this.baseQuery = baseQuery; @@ -156,7 +156,7 @@ private boolean equalsTo(DrillDownQuery other) { } @Override - public Query rewrite(IndexReader r) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { BooleanQuery rewritten = getBooleanQuery(); if (rewritten.clauses().isEmpty()) { return new MatchAllDocsQuery(); diff --git a/lucene/facet/src/java/org/apache/lucene/facet/DrillSidewaysQuery.java b/lucene/facet/src/java/org/apache/lucene/facet/DrillSidewaysQuery.java index 81643019ad93..88850df057ca 100644 --- a/lucene/facet/src/java/org/apache/lucene/facet/DrillSidewaysQuery.java +++ b/lucene/facet/src/java/org/apache/lucene/facet/DrillSidewaysQuery.java @@ -24,7 +24,6 @@ import java.util.List; import java.util.Objects; import org.apache.lucene.facet.DrillSidewaysScorer.DocsAndCost; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.search.BulkScorer; import org.apache.lucene.search.ConstantScoreScorer; @@ -80,8 +79,8 @@ class DrillSidewaysQuery extends Query { } /** - * Needed for {@link #rewrite(IndexReader)}. Ensures the same "managed" lists get used since - * {@link DrillSideways} accesses references to these through the original {@code + * Needed for {@link Query#rewrite(IndexSearcher)}. Ensures the same "managed" lists get used + * since {@link DrillSideways} accesses references to these through the original {@code * DrillSidewaysQuery}. */ private DrillSidewaysQuery( @@ -107,17 +106,17 @@ public String toString(String field) { } @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { Query newQuery = baseQuery; while (true) { - Query rewrittenQuery = newQuery.rewrite(reader); + Query rewrittenQuery = newQuery.rewrite(indexSearcher); if (rewrittenQuery == newQuery) { break; } newQuery = rewrittenQuery; } if (newQuery == baseQuery) { - return super.rewrite(reader); + return super.rewrite(indexSearcher); } else { return new DrillSidewaysQuery( newQuery, diff --git a/lucene/facet/src/java/org/apache/lucene/facet/range/DoubleRange.java b/lucene/facet/src/java/org/apache/lucene/facet/range/DoubleRange.java index bf188a9d80f1..3824baca4d34 100644 --- a/lucene/facet/src/java/org/apache/lucene/facet/range/DoubleRange.java +++ b/lucene/facet/src/java/org/apache/lucene/facet/range/DoubleRange.java @@ -20,7 +20,6 @@ import java.util.Objects; import org.apache.lucene.facet.MultiDoubleValues; import org.apache.lucene.facet.MultiDoubleValuesSource; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.search.ConstantScoreScorer; import org.apache.lucene.search.ConstantScoreWeight; @@ -154,14 +153,14 @@ public void visit(QueryVisitor visitor) { } @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { if (fastMatchQuery != null) { - final Query fastMatchRewritten = fastMatchQuery.rewrite(reader); + final Query fastMatchRewritten = fastMatchQuery.rewrite(indexSearcher); if (fastMatchRewritten != fastMatchQuery) { return new ValueSourceQuery(range, fastMatchRewritten, valueSource); } } - return super.rewrite(reader); + return super.rewrite(indexSearcher); } @Override @@ -252,14 +251,14 @@ public void visit(QueryVisitor visitor) { } @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { if (fastMatchQuery != null) { - final Query fastMatchRewritten = fastMatchQuery.rewrite(reader); + final Query fastMatchRewritten = fastMatchQuery.rewrite(indexSearcher); if (fastMatchRewritten != fastMatchQuery) { return new MultiValueSourceQuery(range, fastMatchRewritten, valueSource); } } - return super.rewrite(reader); + return super.rewrite(indexSearcher); } @Override diff --git a/lucene/facet/src/java/org/apache/lucene/facet/range/LongRange.java b/lucene/facet/src/java/org/apache/lucene/facet/range/LongRange.java index 63e991904378..6796780d010d 100644 --- a/lucene/facet/src/java/org/apache/lucene/facet/range/LongRange.java +++ b/lucene/facet/src/java/org/apache/lucene/facet/range/LongRange.java @@ -20,7 +20,6 @@ import java.util.Objects; import org.apache.lucene.facet.MultiLongValues; import org.apache.lucene.facet.MultiLongValuesSource; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.search.ConstantScoreScorer; import org.apache.lucene.search.ConstantScoreWeight; @@ -141,14 +140,14 @@ public void visit(QueryVisitor visitor) { } @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { if (fastMatchQuery != null) { - final Query fastMatchRewritten = fastMatchQuery.rewrite(reader); + final Query fastMatchRewritten = fastMatchQuery.rewrite(indexSearcher); if (fastMatchRewritten != fastMatchQuery) { return new ValueSourceQuery(range, fastMatchRewritten, valueSource); } } - return super.rewrite(reader); + return super.rewrite(indexSearcher); } @Override @@ -239,14 +238,14 @@ public void visit(QueryVisitor visitor) { } @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { if (fastMatchQuery != null) { - final Query fastMatchRewritten = fastMatchQuery.rewrite(reader); + final Query fastMatchRewritten = fastMatchQuery.rewrite(indexSearcher); if (fastMatchRewritten != fastMatchQuery) { return new MultiValueSourceQuery(range, fastMatchRewritten, valuesSource); } } - return super.rewrite(reader); + return super.rewrite(indexSearcher); } @Override diff --git a/lucene/facet/src/java/org/apache/lucene/facet/range/OverlappingLongRangeCounter.java b/lucene/facet/src/java/org/apache/lucene/facet/range/OverlappingLongRangeCounter.java index 3c9ae7ebd7cb..b478e3994e11 100644 --- a/lucene/facet/src/java/org/apache/lucene/facet/range/OverlappingLongRangeCounter.java +++ b/lucene/facet/src/java/org/apache/lucene/facet/range/OverlappingLongRangeCounter.java @@ -84,7 +84,7 @@ void startMultiValuedDoc() { if (multiValuedDocElementaryIntervalHits == null) { multiValuedDocElementaryIntervalHits = new FixedBitSet(boundaries.length); } else { - multiValuedDocElementaryIntervalHits.clear(0, multiValuedDocElementaryIntervalHits.length()); + multiValuedDocElementaryIntervalHits.clear(); } } @@ -103,7 +103,7 @@ boolean endMultiValuedDoc() { if (multiValuedDocRangeHits == null) { multiValuedDocRangeHits = new FixedBitSet(rangeCount()); } else { - multiValuedDocRangeHits.clear(0, multiValuedDocRangeHits.length()); + multiValuedDocRangeHits.clear(); } elementaryIntervalUpto = 0; rollupMultiValued(root); diff --git a/lucene/facet/src/test/org/apache/lucene/facet/TestDrillDownQuery.java b/lucene/facet/src/test/org/apache/lucene/facet/TestDrillDownQuery.java index fdac9935eeef..d606009d79f0 100644 --- a/lucene/facet/src/test/org/apache/lucene/facet/TestDrillDownQuery.java +++ b/lucene/facet/src/test/org/apache/lucene/facet/TestDrillDownQuery.java @@ -255,7 +255,8 @@ public void testClone() throws Exception { public void testNoDrillDown() throws Exception { Query base = new MatchAllDocsQuery(); DrillDownQuery q = new DrillDownQuery(config, base); - Query rewrite = q.rewrite(reader).rewrite(reader); + IndexSearcher searcher = newSearcher(reader); + Query rewrite = q.rewrite(searcher).rewrite(searcher); assertEquals(base, rewrite); } diff --git a/lucene/facet/src/test/org/apache/lucene/facet/TestDrillSideways.java b/lucene/facet/src/test/org/apache/lucene/facet/TestDrillSideways.java index eb12c2b42eed..1280e2f75114 100644 --- a/lucene/facet/src/test/org/apache/lucene/facet/TestDrillSideways.java +++ b/lucene/facet/src/test/org/apache/lucene/facet/TestDrillSideways.java @@ -740,7 +740,7 @@ protected FacetsCollectorManager createDrillDownFacetsCollectorManager() { Query baseQuery = new TermQuery(new Term("content", "foo")) { @Override - public Query rewrite(IndexReader reader) { + public Query rewrite(IndexSearcher indexSearcher) { // return a new instance, forcing the DrillDownQuery to also rewrite itself, exposing // the bug in LUCENE-9988: return new TermQuery(getTerm()); diff --git a/lucene/facet/src/test/org/apache/lucene/facet/range/TestRangeFacetCounts.java b/lucene/facet/src/test/org/apache/lucene/facet/range/TestRangeFacetCounts.java index 97cf11c8e1ac..ca86e83e41b1 100644 --- a/lucene/facet/src/test/org/apache/lucene/facet/range/TestRangeFacetCounts.java +++ b/lucene/facet/src/test/org/apache/lucene/facet/range/TestRangeFacetCounts.java @@ -1450,12 +1450,12 @@ public int hashCode() { } @Override - public Query rewrite(IndexReader reader) throws IOException { - final Query inRewritten = in.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + final Query inRewritten = in.rewrite(indexSearcher); if (in != inRewritten) { return new UsedQuery(inRewritten, used); } - return super.rewrite(reader); + return super.rewrite(indexSearcher); } @Override diff --git a/lucene/highlighter/src/java/org/apache/lucene/search/highlight/WeightedSpanTermExtractor.java b/lucene/highlighter/src/java/org/apache/lucene/search/highlight/WeightedSpanTermExtractor.java index da77a97ac9fb..7fbe6fbd080d 100644 --- a/lucene/highlighter/src/java/org/apache/lucene/search/highlight/WeightedSpanTermExtractor.java +++ b/lucene/highlighter/src/java/org/apache/lucene/search/highlight/WeightedSpanTermExtractor.java @@ -250,7 +250,7 @@ protected void extract(Query query, float boost, Map t if (query instanceof MultiTermQuery) { rewritten = MultiTermQuery.SCORING_BOOLEAN_REWRITE.rewrite(reader, (MultiTermQuery) query); } else { - rewritten = origQuery.rewrite(reader); + rewritten = origQuery.rewrite(new IndexSearcher(reader)); } if (rewritten != origQuery) { // only rewrite once and then flatten again - the rewritten query could have a special diff --git a/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/MemoryIndexOffsetStrategy.java b/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/MemoryIndexOffsetStrategy.java index aad68190c644..851c4639df80 100644 --- a/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/MemoryIndexOffsetStrategy.java +++ b/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/MemoryIndexOffsetStrategy.java @@ -30,7 +30,7 @@ import org.apache.lucene.index.memory.MemoryIndex; import org.apache.lucene.queries.spans.SpanQuery; import org.apache.lucene.util.BytesRef; -import org.apache.lucene.util.automaton.DaciukMihovAutomatonBuilder; +import org.apache.lucene.util.automaton.Automata; /** * Uses an {@link Analyzer} on content to get offsets and then populates a {@link MemoryIndex}. @@ -67,7 +67,7 @@ private static CharArrayMatcher buildCombinedAutomaton(UHComponents components) // to build an automaton on them List filteredTerms = Arrays.stream(components.getTerms()) - .filter(b -> b.length < DaciukMihovAutomatonBuilder.MAX_TERM_LENGTH) + .filter(b -> b.length < Automata.MAX_STRING_UNION_TERM_LENGTH) .collect(Collectors.toList()); allAutomata.add(CharArrayMatcher.fromTerms(filteredTerms)); } diff --git a/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/UnifiedHighlighter.java b/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/UnifiedHighlighter.java index 0dee795ebc28..615db5ecd5ff 100644 --- a/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/UnifiedHighlighter.java +++ b/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/UnifiedHighlighter.java @@ -1252,11 +1252,11 @@ protected FieldOffsetStrategy getOffsetStrategy( /** * When highlighting phrases accurately, we need to know which {@link SpanQuery}'s need to have - * {@link Query#rewrite(IndexReader)} called on them. It helps performance to avoid it if it's not - * needed. This method will be invoked on all SpanQuery instances recursively. If you have custom - * SpanQuery queries then override this to check instanceof and provide a definitive answer. If - * the query isn't your custom one, simply return null to have the default rules apply, which - * govern the ones included in Lucene. + * {@link Query#rewrite(IndexSearcher)} called on them. It helps performance to avoid it if it's + * not needed. This method will be invoked on all SpanQuery instances recursively. If you have + * custom SpanQuery queries then override this to check instanceof and provide a definitive + * answer. If the query isn't your custom one, simply return null to have the default rules apply, + * which govern the ones included in Lucene. */ protected Boolean requiresRewrite(SpanQuery spanQuery) { return null; diff --git a/lucene/highlighter/src/java/org/apache/lucene/search/vectorhighlight/FieldQuery.java b/lucene/highlighter/src/java/org/apache/lucene/search/vectorhighlight/FieldQuery.java index ff5a11c47d66..851197e42d5e 100644 --- a/lucene/highlighter/src/java/org/apache/lucene/search/vectorhighlight/FieldQuery.java +++ b/lucene/highlighter/src/java/org/apache/lucene/search/vectorhighlight/FieldQuery.java @@ -33,6 +33,7 @@ import org.apache.lucene.search.BoostQuery; import org.apache.lucene.search.ConstantScoreQuery; import org.apache.lucene.search.DisjunctionMaxQuery; +import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.MultiTermQuery; import org.apache.lucene.search.PhraseQuery; import org.apache.lucene.search.Query; @@ -65,8 +66,14 @@ public FieldQuery(Query query, IndexReader reader, boolean phraseHighlight, bool throws IOException { this.fieldMatch = fieldMatch; Set flatQueries = new LinkedHashSet<>(); - flatten(query, reader, flatQueries, 1f); - saveTerms(flatQueries, reader); + IndexSearcher searcher; + if (reader == null) { + searcher = null; + } else { + searcher = new IndexSearcher(reader); + } + flatten(query, searcher, flatQueries, 1f); + saveTerms(flatQueries, searcher); Collection expandQueries = expand(flatQueries); for (Query flatQuery : expandQueries) { @@ -96,7 +103,7 @@ public FieldQuery(Query query, IndexReader reader, boolean phraseHighlight, bool } protected void flatten( - Query sourceQuery, IndexReader reader, Collection flatQueries, float boost) + Query sourceQuery, IndexSearcher searcher, Collection flatQueries, float boost) throws IOException { while (sourceQuery instanceof BoostQuery) { BoostQuery bq = (BoostQuery) sourceQuery; @@ -107,13 +114,13 @@ protected void flatten( BooleanQuery bq = (BooleanQuery) sourceQuery; for (BooleanClause clause : bq) { if (!clause.isProhibited()) { - flatten(clause.getQuery(), reader, flatQueries, boost); + flatten(clause.getQuery(), searcher, flatQueries, boost); } } } else if (sourceQuery instanceof DisjunctionMaxQuery) { DisjunctionMaxQuery dmq = (DisjunctionMaxQuery) sourceQuery; for (Query query : dmq) { - flatten(query, reader, flatQueries, boost); + flatten(query, searcher, flatQueries, boost); } } else if (sourceQuery instanceof TermQuery) { if (boost != 1f) { @@ -123,7 +130,7 @@ protected void flatten( } else if (sourceQuery instanceof SynonymQuery) { SynonymQuery synQuery = (SynonymQuery) sourceQuery; for (Term term : synQuery.getTerms()) { - flatten(new TermQuery(term), reader, flatQueries, boost); + flatten(new TermQuery(term), searcher, flatQueries, boost); } } else if (sourceQuery instanceof PhraseQuery) { PhraseQuery pq = (PhraseQuery) sourceQuery; @@ -135,28 +142,28 @@ protected void flatten( } else if (sourceQuery instanceof ConstantScoreQuery) { final Query q = ((ConstantScoreQuery) sourceQuery).getQuery(); if (q != null) { - flatten(q, reader, flatQueries, boost); + flatten(q, searcher, flatQueries, boost); } } else if (sourceQuery instanceof FunctionScoreQuery) { final Query q = ((FunctionScoreQuery) sourceQuery).getWrappedQuery(); if (q != null) { - flatten(q, reader, flatQueries, boost); + flatten(q, searcher, flatQueries, boost); } - } else if (reader != null) { + } else if (searcher != null) { Query query = sourceQuery; Query rewritten; if (sourceQuery instanceof MultiTermQuery) { rewritten = new MultiTermQuery.TopTermsScoringBooleanQueryRewrite(MAX_MTQ_TERMS) - .rewrite(reader, (MultiTermQuery) query); + .rewrite(searcher.getIndexReader(), (MultiTermQuery) query); } else { - rewritten = query.rewrite(reader); + rewritten = query.rewrite(searcher); } if (rewritten != query) { // only rewrite once and then flatten again - the rewritten query could have a speacial // treatment // if this method is overwritten in a subclass. - flatten(rewritten, reader, flatQueries, boost); + flatten(rewritten, searcher, flatQueries, boost); } // if the query is already rewritten we discard it } @@ -311,7 +318,7 @@ else if (query instanceof PhraseQuery) { * - fieldMatch==false * termSetMap=Map> */ - void saveTerms(Collection flatQueries, IndexReader reader) throws IOException { + void saveTerms(Collection flatQueries, IndexSearcher searcher) throws IOException { for (Query query : flatQueries) { while (query instanceof BoostQuery) { query = ((BoostQuery) query).getQuery(); @@ -320,8 +327,8 @@ void saveTerms(Collection flatQueries, IndexReader reader) throws IOExcep if (query instanceof TermQuery) termSet.add(((TermQuery) query).getTerm().text()); else if (query instanceof PhraseQuery) { for (Term term : ((PhraseQuery) query).getTerms()) termSet.add(term.text()); - } else if (query instanceof MultiTermQuery && reader != null) { - BooleanQuery mtqTerms = (BooleanQuery) query.rewrite(reader); + } else if (query instanceof MultiTermQuery && searcher != null) { + BooleanQuery mtqTerms = (BooleanQuery) query.rewrite(searcher); for (BooleanClause clause : mtqTerms) { termSet.add(((TermQuery) clause.getQuery()).getTerm().text()); } diff --git a/lucene/highlighter/src/test/org/apache/lucene/search/highlight/TestHighlighter.java b/lucene/highlighter/src/test/org/apache/lucene/search/highlight/TestHighlighter.java index cb1e640f3551..1664eb4be67d 100644 --- a/lucene/highlighter/src/test/org/apache/lucene/search/highlight/TestHighlighter.java +++ b/lucene/highlighter/src/test/org/apache/lucene/search/highlight/TestHighlighter.java @@ -261,7 +261,7 @@ public void testHighlightUnknownQueryAfterRewrite() new Query() { @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { CommonTermsQuery query = new CommonTermsQuery(Occur.MUST, Occur.SHOULD, 3); query.add(new Term(FIELD_NAME, "this")); // stop-word query.add(new Term(FIELD_NAME, "long")); @@ -2223,7 +2223,7 @@ public void doSearching(Query unReWrittenQuery) throws Exception { searcher = newSearcher(reader); // for any multi-term queries to work (prefix, wildcard, range,fuzzy etc) // you must use a rewritten query! - query = unReWrittenQuery.rewrite(reader); + query = unReWrittenQuery.rewrite(searcher); if (VERBOSE) System.out.println("Searching for: " + query.toString(FIELD_NAME)); hits = searcher.search(query, 1000); } diff --git a/lucene/highlighter/src/test/org/apache/lucene/search/highlight/custom/TestHighlightCustomQuery.java b/lucene/highlighter/src/test/org/apache/lucene/search/highlight/custom/TestHighlightCustomQuery.java index 97e0baf6e912..37235bdb6110 100644 --- a/lucene/highlighter/src/test/org/apache/lucene/search/highlight/custom/TestHighlightCustomQuery.java +++ b/lucene/highlighter/src/test/org/apache/lucene/search/highlight/custom/TestHighlightCustomQuery.java @@ -21,9 +21,9 @@ import java.util.Map; import java.util.Objects; import org.apache.lucene.analysis.TokenStream; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.Term; import org.apache.lucene.search.BoostQuery; +import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.TermQuery; @@ -167,7 +167,7 @@ public String toString(String field) { } @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { return new TermQuery(term); } diff --git a/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighter.java b/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighter.java index f831fbf77a7f..54792a569f76 100644 --- a/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighter.java +++ b/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighter.java @@ -58,7 +58,7 @@ import org.apache.lucene.tests.analysis.MockTokenizer; import org.apache.lucene.tests.index.RandomIndexWriter; import org.apache.lucene.tests.util.LuceneTestCase; -import org.apache.lucene.util.automaton.DaciukMihovAutomatonBuilder; +import org.apache.lucene.util.automaton.Automata; import org.junit.After; import org.junit.Before; @@ -1619,7 +1619,7 @@ public String toString(String field) { } @Override - public Query rewrite(IndexReader reader) { + public Query rewrite(IndexSearcher indexSearcher) { return this; } @@ -1671,12 +1671,11 @@ public void testQueryWithLongTerm() throws IOException { Query query = new BooleanQuery.Builder() .add( - new TermQuery( - new Term("title", "a".repeat(DaciukMihovAutomatonBuilder.MAX_TERM_LENGTH))), + new TermQuery(new Term("title", "a".repeat(Automata.MAX_STRING_UNION_TERM_LENGTH))), BooleanClause.Occur.SHOULD) .add( new TermQuery( - new Term("title", "a".repeat(DaciukMihovAutomatonBuilder.MAX_TERM_LENGTH + 1))), + new Term("title", "a".repeat(Automata.MAX_STRING_UNION_TERM_LENGTH + 1))), BooleanClause.Occur.SHOULD) .add(new TermQuery(new Term("title", "title")), BooleanClause.Occur.SHOULD) .build(); diff --git a/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterMTQ.java b/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterMTQ.java index 4f7bd056ca19..4aabf26d45bc 100644 --- a/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterMTQ.java +++ b/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterMTQ.java @@ -1111,8 +1111,8 @@ public void visit(QueryVisitor visitor) { } @Override - public Query rewrite(IndexReader reader) throws IOException { - Query newOriginalQuery = originalQuery.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + Query newOriginalQuery = originalQuery.rewrite(indexSearcher); if (newOriginalQuery != originalQuery) { return new MyWrapperSpanQuery((SpanQuery) newOriginalQuery); } diff --git a/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterStrictPhrases.java b/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterStrictPhrases.java index 8116ece1c1c0..9f189a215b88 100644 --- a/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterStrictPhrases.java +++ b/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterStrictPhrases.java @@ -658,8 +658,8 @@ public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float bo } @Override - public Query rewrite(IndexReader reader) throws IOException { - Query newWrapped = wrapped.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + Query newWrapped = wrapped.rewrite(indexSearcher); if (newWrapped != wrapped) { return new MyQuery(newWrapped); } diff --git a/lucene/highlighter/src/test/org/apache/lucene/search/vectorhighlight/AbstractTestCase.java b/lucene/highlighter/src/test/org/apache/lucene/search/vectorhighlight/AbstractTestCase.java index 8542a45aab7b..9a2f8a9e4faa 100644 --- a/lucene/highlighter/src/test/org/apache/lucene/search/vectorhighlight/AbstractTestCase.java +++ b/lucene/highlighter/src/test/org/apache/lucene/search/vectorhighlight/AbstractTestCase.java @@ -21,7 +21,9 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; -import org.apache.lucene.analysis.*; +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.analysis.TokenStream; +import org.apache.lucene.analysis.Tokenizer; import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; import org.apache.lucene.analysis.tokenattributes.OffsetAttribute; import org.apache.lucene.analysis.tokenattributes.TermToBytesRefAttribute; @@ -37,6 +39,7 @@ import org.apache.lucene.index.Term; import org.apache.lucene.search.BoostQuery; import org.apache.lucene.search.DisjunctionMaxQuery; +import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.PhraseQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.TermQuery; @@ -56,6 +59,7 @@ public abstract class AbstractTestCase extends LuceneTestCase { protected Analyzer analyzerB; protected Analyzer analyzerK; protected IndexReader reader; + protected IndexSearcher searcher; protected static final String[] shortMVValues = { "", "", "a b c", "", // empty data in multi valued field @@ -343,6 +347,7 @@ protected void make1dmfIndex(Analyzer analyzer, String... values) throws Excepti writer.close(); if (reader != null) reader.close(); reader = DirectoryReader.open(dir); + searcher = newSearcher(reader); } // make 1 doc with multi valued & not analyzed field @@ -363,6 +368,7 @@ protected void make1dmfIndexNA(String... values) throws Exception { writer.close(); if (reader != null) reader.close(); reader = DirectoryReader.open(dir); + searcher = newSearcher(reader); } protected void makeIndexShortMV() throws Exception { diff --git a/lucene/highlighter/src/test/org/apache/lucene/search/vectorhighlight/TestFieldQuery.java b/lucene/highlighter/src/test/org/apache/lucene/search/vectorhighlight/TestFieldQuery.java index 42fec6dba55f..6538c0d2985f 100644 --- a/lucene/highlighter/src/test/org/apache/lucene/search/vectorhighlight/TestFieldQuery.java +++ b/lucene/highlighter/src/test/org/apache/lucene/search/vectorhighlight/TestFieldQuery.java @@ -63,7 +63,7 @@ public void testFlattenBoolean() throws Exception { FieldQuery fq = new FieldQuery(booleanQuery, true, true); Set flatQueries = new HashSet<>(); - fq.flatten(booleanQuery, reader, flatQueries, 1f); + fq.flatten(booleanQuery, searcher, flatQueries, 1f); assertCollectionQueries(flatQueries, tq(boost, "A"), tq(boost, "B"), tq(boost, "C")); } @@ -73,7 +73,7 @@ public void testFlattenDisjunctionMaxQuery() throws Exception { query = new BoostQuery(query, boost); FieldQuery fq = new FieldQuery(query, true, true); Set flatQueries = new HashSet<>(); - fq.flatten(query, reader, flatQueries, 1f); + fq.flatten(query, searcher, flatQueries, 1f); assertCollectionQueries(flatQueries, tq(boost, "A"), tq(boost, "B"), pqF(boost, "C", "D")); } @@ -87,7 +87,7 @@ public void testFlattenTermAndPhrase() throws Exception { FieldQuery fq = new FieldQuery(booleanQuery, true, true); Set flatQueries = new HashSet<>(); - fq.flatten(booleanQuery, reader, flatQueries, 1f); + fq.flatten(booleanQuery, searcher, flatQueries, 1f); assertCollectionQueries(flatQueries, tq(boost, "A"), pqF(boost, "B", "C")); } @@ -99,7 +99,7 @@ public void testFlattenTermAndPhrase2gram() throws Exception { FieldQuery fq = new FieldQuery(query.build(), true, true); Set flatQueries = new HashSet<>(); - fq.flatten(query.build(), reader, flatQueries, 1f); + fq.flatten(query.build(), searcher, flatQueries, 1f); assertCollectionQueries(flatQueries, tq("AA"), pqF("BC", "CD"), pqF("EF", "FG", "GH")); } @@ -107,7 +107,7 @@ public void testFlatten1TermPhrase() throws Exception { Query query = pqF("A"); FieldQuery fq = new FieldQuery(query, true, true); Set flatQueries = new HashSet<>(); - fq.flatten(query, reader, flatQueries, 1f); + fq.flatten(query, searcher, flatQueries, 1f); assertCollectionQueries(flatQueries, tq("A")); } @@ -950,7 +950,7 @@ public void testFlattenConstantScoreQuery() throws Exception { query = new BoostQuery(query, boost); FieldQuery fq = new FieldQuery(query, true, true); Set flatQueries = new HashSet<>(); - fq.flatten(query, reader, flatQueries, 1f); + fq.flatten(query, searcher, flatQueries, 1f); assertCollectionQueries(flatQueries, tq(boost, "A")); } } diff --git a/lucene/join/src/java/org/apache/lucene/search/join/ParentChildrenBlockJoinQuery.java b/lucene/join/src/java/org/apache/lucene/search/join/ParentChildrenBlockJoinQuery.java index 9ba6daee284a..64f5e5ba1169 100644 --- a/lucene/join/src/java/org/apache/lucene/search/join/ParentChildrenBlockJoinQuery.java +++ b/lucene/join/src/java/org/apache/lucene/search/join/ParentChildrenBlockJoinQuery.java @@ -18,7 +18,6 @@ package org.apache.lucene.search.join; import java.io.IOException; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.ReaderUtil; import org.apache.lucene.search.DocIdSetIterator; @@ -88,12 +87,12 @@ public void visit(QueryVisitor visitor) { } @Override - public Query rewrite(IndexReader reader) throws IOException { - final Query childRewrite = childQuery.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + final Query childRewrite = childQuery.rewrite(indexSearcher); if (childRewrite != childQuery) { return new ParentChildrenBlockJoinQuery(parentFilter, childRewrite, parentDocId); } else { - return super.rewrite(reader); + return super.rewrite(indexSearcher); } } diff --git a/lucene/join/src/java/org/apache/lucene/search/join/ToChildBlockJoinQuery.java b/lucene/join/src/java/org/apache/lucene/search/join/ToChildBlockJoinQuery.java index 42c41efcefa2..3f2a9e76c54b 100644 --- a/lucene/join/src/java/org/apache/lucene/search/join/ToChildBlockJoinQuery.java +++ b/lucene/join/src/java/org/apache/lucene/search/join/ToChildBlockJoinQuery.java @@ -20,7 +20,6 @@ import java.util.Collection; import java.util.Collections; import java.util.Locale; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.Explanation; @@ -305,12 +304,12 @@ int getParentDoc() { } @Override - public Query rewrite(IndexReader reader) throws IOException { - final Query parentRewrite = parentQuery.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + final Query parentRewrite = parentQuery.rewrite(indexSearcher); if (parentRewrite != parentQuery) { return new ToChildBlockJoinQuery(parentRewrite, parentsFilter); } else { - return super.rewrite(reader); + return super.rewrite(indexSearcher); } } diff --git a/lucene/join/src/java/org/apache/lucene/search/join/ToParentBlockJoinQuery.java b/lucene/join/src/java/org/apache/lucene/search/join/ToParentBlockJoinQuery.java index 5640c9e4a7cd..6134cd0e1dde 100644 --- a/lucene/join/src/java/org/apache/lucene/search/join/ToParentBlockJoinQuery.java +++ b/lucene/join/src/java/org/apache/lucene/search/join/ToParentBlockJoinQuery.java @@ -22,7 +22,6 @@ import java.util.Collection; import java.util.Collections; import java.util.Locale; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.search.ConstantScoreQuery; @@ -173,7 +172,7 @@ public long cost() { public Explanation explain(LeafReaderContext context, int doc) throws IOException { BlockJoinScorer scorer = (BlockJoinScorer) scorer(context); if (scorer != null && scorer.iterator().advance(doc) == doc) { - return scorer.explain(context, in); + return scorer.explain(context, in, scoreMode); } return Explanation.noMatch("Not a match"); } @@ -392,45 +391,61 @@ private void setScoreAndFreq() throws IOException { } this.score = (float) score; } - - public Explanation explain(LeafReaderContext context, Weight childWeight) throws IOException { + /* + * This instance of Explanation requires three parameters, context, childWeight, and scoreMode. + * The scoreMode parameter considers Avg, Total, Min, Max, and None. + * */ + public Explanation explain(LeafReaderContext context, Weight childWeight, ScoreMode scoreMode) + throws IOException { int prevParentDoc = parentBits.prevSetBit(parentApproximation.docID() - 1); int start = context.docBase + prevParentDoc + 1; // +1 b/c prevParentDoc is previous parent doc int end = context.docBase + parentApproximation.docID() - 1; // -1 b/c parentDoc is parent doc Explanation bestChild = null; + Explanation worstChild = null; + int matches = 0; for (int childDoc = start; childDoc <= end; childDoc++) { Explanation child = childWeight.explain(context, childDoc - context.docBase); if (child.isMatch()) { matches++; if (bestChild == null - || child.getValue().floatValue() > bestChild.getValue().floatValue()) { + || child.getValue().doubleValue() > bestChild.getValue().doubleValue()) { bestChild = child; } + if (worstChild == null + || child.getValue().doubleValue() < worstChild.getValue().doubleValue()) { + worstChild = child; + } } } - + assert matches > 0 : "No matches should be handled before."; + Explanation subExplain = scoreMode == ScoreMode.Min ? worstChild : bestChild; return Explanation.match( - score(), - String.format( - Locale.ROOT, - "Score based on %d child docs in range from %d to %d, best match:", - matches, - start, - end), - bestChild); + this.score(), + formatScoreExplanation(matches, start, end, scoreMode), + subExplain == null ? Collections.emptyList() : Collections.singleton(subExplain)); + } + + private String formatScoreExplanation(int matches, int start, int end, ScoreMode scoreMode) { + return String.format( + Locale.ROOT, + "Score based on %d child docs in range from %d to %d, using score mode %s", + matches, + start, + end, + scoreMode); } } @Override - public Query rewrite(IndexReader reader) throws IOException { - final Query childRewrite = childQuery.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + final Query childRewrite = childQuery.rewrite(indexSearcher); if (childRewrite != childQuery) { return new ToParentBlockJoinQuery(childRewrite, parentsFilter, scoreMode); } else { - return super.rewrite(reader); + return super.rewrite(indexSearcher); } } diff --git a/lucene/join/src/test/org/apache/lucene/search/join/TestBlockJoin.java b/lucene/join/src/test/org/apache/lucene/search/join/TestBlockJoin.java index b77e634aac20..ca4246196fce 100644 --- a/lucene/join/src/test/org/apache/lucene/search/join/TestBlockJoin.java +++ b/lucene/join/src/test/org/apache/lucene/search/join/TestBlockJoin.java @@ -277,7 +277,6 @@ public void testSimple() throws Exception { CheckHits.checkHitCollector(random(), fullQuery.build(), "country", s, new int[] {2}); TopDocs topDocs = s.search(fullQuery.build(), 1); - // assertEquals(1, results.totalHitCount); assertEquals(1, topDocs.totalHits.value); Document parentDoc = s.storedFields().document(topDocs.scoreDocs[0].doc); @@ -890,13 +889,11 @@ public void testRandom() throws Exception { Explanation explanation = joinS.explain(childJoinQuery, hit.doc); Document document = joinS.storedFields().document(hit.doc - 1); int childId = Integer.parseInt(document.get("childID")); - // System.out.println(" hit docID=" + hit.doc + " childId=" + childId + " parentId=" + - // document.get("parentID")); assertTrue(explanation.isMatch()); assertEquals(hit.score, explanation.getValue().doubleValue(), 0.0f); Matcher m = Pattern.compile( - "Score based on ([0-9]+) child docs in range from ([0-9]+) to ([0-9]+), best match:") + "Score based on ([0-9]+) child docs in range from ([0-9]+) to ([0-9]+), using score mode (None|Avg|Min|Max|Total)") .matcher(explanation.getDescription()); assertTrue("Block Join description not matches", m.matches()); assertTrue("Matched children not positive", Integer.parseInt(m.group(1)) > 0); diff --git a/lucene/luke/src/java/org/apache/lucene/luke/models/search/SearchImpl.java b/lucene/luke/src/java/org/apache/lucene/luke/models/search/SearchImpl.java index 9936d6924150..fa552e65d3f0 100644 --- a/lucene/luke/src/java/org/apache/lucene/luke/models/search/SearchImpl.java +++ b/lucene/luke/src/java/org/apache/lucene/luke/models/search/SearchImpl.java @@ -152,7 +152,7 @@ public Query parseQuery( if (rewrite) { try { - query = query.rewrite(reader); + query = query.rewrite(searcher); } catch (IOException e) { throw new LukeException( String.format(Locale.ENGLISH, "Failed to rewrite query: %s", query.toString()), e); diff --git a/lucene/misc/src/test/org/apache/lucene/misc/search/TestDiversifiedTopDocsCollector.java b/lucene/misc/src/test/org/apache/lucene/misc/search/TestDiversifiedTopDocsCollector.java index e561346f8cf1..ca63678fd2b3 100644 --- a/lucene/misc/src/test/org/apache/lucene/misc/search/TestDiversifiedTopDocsCollector.java +++ b/lucene/misc/src/test/org/apache/lucene/misc/search/TestDiversifiedTopDocsCollector.java @@ -499,12 +499,12 @@ public int hashCode() { } @Override - public Query rewrite(IndexReader reader) throws IOException { - Query rewritten = query.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + Query rewritten = query.rewrite(indexSearcher); if (rewritten != query) { return new DocValueScoreQuery(rewritten, scoreField); } - return super.rewrite(reader); + return super.rewrite(indexSearcher); } @Override diff --git a/lucene/monitor/src/java/org/apache/lucene/monitor/ForceNoBulkScoringQuery.java b/lucene/monitor/src/java/org/apache/lucene/monitor/ForceNoBulkScoringQuery.java index 2af23b4a5616..a97d1054c4c9 100644 --- a/lucene/monitor/src/java/org/apache/lucene/monitor/ForceNoBulkScoringQuery.java +++ b/lucene/monitor/src/java/org/apache/lucene/monitor/ForceNoBulkScoringQuery.java @@ -19,7 +19,6 @@ import java.io.IOException; import java.util.Objects; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.search.*; import org.apache.lucene.search.Matches; @@ -34,10 +33,10 @@ public ForceNoBulkScoringQuery(Query inner) { } @Override - public Query rewrite(IndexReader reader) throws IOException { - Query rewritten = inner.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + Query rewritten = inner.rewrite(indexSearcher); if (rewritten != inner) return new ForceNoBulkScoringQuery(rewritten); - return super.rewrite(reader); + return super.rewrite(indexSearcher); } @Override diff --git a/lucene/monitor/src/test/org/apache/lucene/monitor/MonitorTestBase.java b/lucene/monitor/src/test/org/apache/lucene/monitor/MonitorTestBase.java index 65017e732470..548c417aafea 100644 --- a/lucene/monitor/src/test/org/apache/lucene/monitor/MonitorTestBase.java +++ b/lucene/monitor/src/test/org/apache/lucene/monitor/MonitorTestBase.java @@ -22,9 +22,9 @@ import java.util.Map; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.queryparser.classic.ParseException; import org.apache.lucene.queryparser.classic.QueryParser; +import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.tests.util.LuceneTestCase; @@ -65,7 +65,7 @@ protected Monitor newMonitor(Analyzer analyzer) throws IOException { public static class ThrowOnRewriteQuery extends Query { @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { throw new IOException("Error rewriting"); } diff --git a/lucene/monitor/src/test/org/apache/lucene/monitor/TestForceNoBulkScoringQuery.java b/lucene/monitor/src/test/org/apache/lucene/monitor/TestForceNoBulkScoringQuery.java index 28f96c760b33..4f5011ba17e7 100644 --- a/lucene/monitor/src/test/org/apache/lucene/monitor/TestForceNoBulkScoringQuery.java +++ b/lucene/monitor/src/test/org/apache/lucene/monitor/TestForceNoBulkScoringQuery.java @@ -67,7 +67,7 @@ public void testRewrite() throws IOException { assertEquals(q.getWrappedQuery(), pq); - Query rewritten = q.rewrite(reader); + Query rewritten = q.rewrite(newSearcher(reader)); assertTrue(rewritten instanceof ForceNoBulkScoringQuery); Query inner = ((ForceNoBulkScoringQuery) rewritten).getWrappedQuery(); diff --git a/lucene/queries/src/java/org/apache/lucene/queries/CommonTermsQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/CommonTermsQuery.java index 46a7f45069ad..b6ff82dce38d 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/CommonTermsQuery.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/CommonTermsQuery.java @@ -30,6 +30,7 @@ import org.apache.lucene.search.BooleanClause.Occur; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.BoostQuery; +import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.QueryVisitor; @@ -101,7 +102,8 @@ public void add(Term term) { } @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + IndexReader reader = indexSearcher.getIndexReader(); if (this.terms.isEmpty()) { return new MatchNoDocsQuery("CommonTermsQuery with no terms"); } else if (this.terms.size() == 1) { diff --git a/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionScoreQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionScoreQuery.java index f5f03d202919..449188091bd6 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionScoreQuery.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionScoreQuery.java @@ -19,7 +19,6 @@ import java.io.IOException; import java.util.Objects; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.DoubleValues; @@ -122,8 +121,8 @@ public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float bo } @Override - public Query rewrite(IndexReader reader) throws IOException { - Query rewritten = in.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + Query rewritten = in.rewrite(indexSearcher); if (rewritten == in) { return this; } diff --git a/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionValues.java b/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionValues.java index 0d0a99919006..6b2a8a1f546c 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionValues.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/function/FunctionValues.java @@ -70,6 +70,14 @@ public boolean boolVal(int doc) throws IOException { return intVal(doc) != 0; } + public float[] floatVectorVal(int doc) throws IOException { + throw new UnsupportedOperationException(); + } + + public byte[] byteVectorVal(int doc) throws IOException { + throw new UnsupportedOperationException(); + } + /** * returns the bytes representation of the string val - TODO: should this return the indexed raw * bytes not? diff --git a/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/ByteKnnVectorFieldSource.java b/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/ByteKnnVectorFieldSource.java new file mode 100644 index 000000000000..c8a4a93a2dfc --- /dev/null +++ b/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/ByteKnnVectorFieldSource.java @@ -0,0 +1,84 @@ +/* + * 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.queries.function.valuesource; + +import java.io.IOException; +import java.util.Map; +import java.util.Objects; +import org.apache.lucene.index.ByteVectorValues; +import org.apache.lucene.index.LeafReaderContext; +import org.apache.lucene.queries.function.FunctionValues; +import org.apache.lucene.queries.function.ValueSource; +import org.apache.lucene.search.DocIdSetIterator; + +/** + * An implementation for retrieving {@link FunctionValues} instances for byte knn vectors fields. + */ +public class ByteKnnVectorFieldSource extends ValueSource { + private final String fieldName; + + public ByteKnnVectorFieldSource(String fieldName) { + this.fieldName = fieldName; + } + + @Override + public FunctionValues getValues(Map context, LeafReaderContext readerContext) + throws IOException { + + final ByteVectorValues vectorValues = readerContext.reader().getByteVectorValues(fieldName); + + if (vectorValues == null) { + throw new IllegalArgumentException( + "no byte vector value is indexed for field '" + fieldName + "'"); + } + + return new VectorFieldFunction(this) { + + @Override + public byte[] byteVectorVal(int doc) throws IOException { + if (exists(doc)) { + return vectorValues.vectorValue(); + } else { + return null; + } + } + + @Override + protected DocIdSetIterator getVectorIterator() { + return vectorValues; + } + }; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ByteKnnVectorFieldSource other = (ByteKnnVectorFieldSource) o; + return Objects.equals(fieldName, other.fieldName); + } + + @Override + public int hashCode() { + return Objects.hash(getClass().hashCode(), fieldName); + } + + @Override + public String description() { + return "ByteKnnVectorFieldSource(" + fieldName + ")"; + } +} diff --git a/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/ByteVectorSimilarityFunction.java b/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/ByteVectorSimilarityFunction.java new file mode 100644 index 000000000000..fb6ec68ee9e5 --- /dev/null +++ b/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/ByteVectorSimilarityFunction.java @@ -0,0 +1,49 @@ +/* + * 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.queries.function.valuesource; + +import java.io.IOException; +import org.apache.lucene.queries.function.FunctionValues; +import org.apache.lucene.queries.function.ValueSource; + +/** + * ByteVectorSimilarityFunction returns a similarity function between two knn vectors + * with byte elements. + */ +public class ByteVectorSimilarityFunction extends VectorSimilarityFunction { + public ByteVectorSimilarityFunction( + org.apache.lucene.index.VectorSimilarityFunction similarityFunction, + ValueSource vector1, + ValueSource vector2) { + super(similarityFunction, vector1, vector2); + } + + @Override + protected float func(int doc, FunctionValues f1, FunctionValues f2) throws IOException { + + var v1 = f1.byteVectorVal(doc); + var v2 = f2.byteVectorVal(doc); + + if (v1 == null || v2 == null) { + return 0.f; + } + + assert v1.length == v2.length : "Vectors must have the same length"; + + return similarityFunction.compare(v1, v2); + } +} diff --git a/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/ConstKnnByteVectorValueSource.java b/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/ConstKnnByteVectorValueSource.java new file mode 100644 index 000000000000..4996e026abee --- /dev/null +++ b/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/ConstKnnByteVectorValueSource.java @@ -0,0 +1,73 @@ +/* + * 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.queries.function.valuesource; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Map; +import java.util.Objects; +import org.apache.lucene.index.LeafReaderContext; +import org.apache.lucene.queries.function.FunctionValues; +import org.apache.lucene.queries.function.ValueSource; + +/** Function that returns a constant byte vector value for every document. */ +public class ConstKnnByteVectorValueSource extends ValueSource { + private final byte[] vector; + + public ConstKnnByteVectorValueSource(byte[] constVector) { + this.vector = Objects.requireNonNull(constVector, "constVector"); + } + + @Override + public FunctionValues getValues(Map context, LeafReaderContext readerContext) + throws IOException { + return new FunctionValues() { + @Override + public byte[] byteVectorVal(int doc) { + return vector; + } + + @Override + public String strVal(int doc) { + return Arrays.toString(vector); + } + + @Override + public String toString(int doc) throws IOException { + return description() + '=' + strVal(doc); + } + }; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ConstKnnByteVectorValueSource other = (ConstKnnByteVectorValueSource) o; + return Arrays.equals(vector, other.vector); + } + + @Override + public int hashCode() { + return Objects.hash(getClass().hashCode(), Arrays.hashCode(vector)); + } + + @Override + public String description() { + return "ConstKnnByteVectorValueSource(" + Arrays.toString(vector) + ')'; + } +} diff --git a/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/ConstKnnFloatValueSource.java b/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/ConstKnnFloatValueSource.java new file mode 100644 index 000000000000..57c016eb793e --- /dev/null +++ b/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/ConstKnnFloatValueSource.java @@ -0,0 +1,74 @@ +/* + * 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.queries.function.valuesource; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Map; +import java.util.Objects; +import org.apache.lucene.index.LeafReaderContext; +import org.apache.lucene.queries.function.FunctionValues; +import org.apache.lucene.queries.function.ValueSource; +import org.apache.lucene.util.VectorUtil; + +/** Function that returns a constant float vector value for every document. */ +public class ConstKnnFloatValueSource extends ValueSource { + private final float[] vector; + + public ConstKnnFloatValueSource(float[] constVector) { + this.vector = VectorUtil.checkFinite(Objects.requireNonNull(constVector, "constVector")); + } + + @Override + public FunctionValues getValues(Map context, LeafReaderContext readerContext) + throws IOException { + return new FunctionValues() { + @Override + public float[] floatVectorVal(int doc) { + return vector; + } + + @Override + public String strVal(int doc) { + return Arrays.toString(vector); + } + + @Override + public String toString(int doc) throws IOException { + return description() + '=' + strVal(doc); + } + }; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ConstKnnFloatValueSource other = (ConstKnnFloatValueSource) o; + return Arrays.equals(vector, other.vector); + } + + @Override + public int hashCode() { + return Objects.hash(getClass().hashCode(), Arrays.hashCode(vector)); + } + + @Override + public String description() { + return "ConstKnnFloatValueSource(" + Arrays.toString(vector) + ')'; + } +} diff --git a/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/FloatKnnVectorFieldSource.java b/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/FloatKnnVectorFieldSource.java new file mode 100644 index 000000000000..9a1f27a7c79d --- /dev/null +++ b/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/FloatKnnVectorFieldSource.java @@ -0,0 +1,83 @@ +/* + * 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.queries.function.valuesource; + +import java.io.IOException; +import java.util.Map; +import java.util.Objects; +import org.apache.lucene.index.FloatVectorValues; +import org.apache.lucene.index.LeafReaderContext; +import org.apache.lucene.queries.function.FunctionValues; +import org.apache.lucene.queries.function.ValueSource; +import org.apache.lucene.search.DocIdSetIterator; + +/** + * An implementation for retrieving {@link FunctionValues} instances for float knn vectors fields. + */ +public class FloatKnnVectorFieldSource extends ValueSource { + private final String fieldName; + + public FloatKnnVectorFieldSource(String fieldName) { + this.fieldName = fieldName; + } + + @Override + public FunctionValues getValues(Map context, LeafReaderContext readerContext) + throws IOException { + + final FloatVectorValues vectorValues = readerContext.reader().getFloatVectorValues(fieldName); + + if (vectorValues == null) { + throw new IllegalArgumentException( + "no float vector value is indexed for field '" + fieldName + "'"); + } + return new VectorFieldFunction(this) { + + @Override + public float[] floatVectorVal(int doc) throws IOException { + if (exists(doc)) { + return vectorValues.vectorValue(); + } else { + return null; + } + } + + @Override + protected DocIdSetIterator getVectorIterator() { + return vectorValues; + } + }; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + FloatKnnVectorFieldSource other = (FloatKnnVectorFieldSource) o; + return Objects.equals(fieldName, other.fieldName); + } + + @Override + public int hashCode() { + return Objects.hash(getClass().hashCode(), fieldName); + } + + @Override + public String description() { + return "FloatKnnVectorFieldSource(" + fieldName + ")"; + } +} diff --git a/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/FloatVectorSimilarityFunction.java b/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/FloatVectorSimilarityFunction.java new file mode 100644 index 000000000000..296775388856 --- /dev/null +++ b/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/FloatVectorSimilarityFunction.java @@ -0,0 +1,48 @@ +/* + * 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.queries.function.valuesource; + +import java.io.IOException; +import org.apache.lucene.queries.function.FunctionValues; +import org.apache.lucene.queries.function.ValueSource; + +/** + * FloatVectorSimilarityFunction returns a similarity function between two knn vectors + * with float elements. + */ +public class FloatVectorSimilarityFunction extends VectorSimilarityFunction { + public FloatVectorSimilarityFunction( + org.apache.lucene.index.VectorSimilarityFunction similarityFunction, + ValueSource vector1, + ValueSource vector2) { + super(similarityFunction, vector1, vector2); + } + + @Override + protected float func(int doc, FunctionValues f1, FunctionValues f2) throws IOException { + + var v1 = f1.floatVectorVal(doc); + var v2 = f2.floatVectorVal(doc); + + if (v1 == null || v2 == null) { + return 0.f; + } + + assert v1.length == v2.length : "Vectors must have the same length"; + return similarityFunction.compare(v1, v2); + } +} diff --git a/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/VectorFieldFunction.java b/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/VectorFieldFunction.java new file mode 100644 index 000000000000..de64984249fe --- /dev/null +++ b/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/VectorFieldFunction.java @@ -0,0 +1,56 @@ +/* + * 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.queries.function.valuesource; + +import java.io.IOException; +import org.apache.lucene.queries.function.FunctionValues; +import org.apache.lucene.queries.function.ValueSource; +import org.apache.lucene.search.DocIdSetIterator; + +/** An implementation for retrieving {@link FunctionValues} instances for knn vectors fields. */ +public abstract class VectorFieldFunction extends FunctionValues { + + protected final ValueSource valueSource; + int lastDocID; + + protected VectorFieldFunction(ValueSource valueSource) { + this.valueSource = valueSource; + } + + protected abstract DocIdSetIterator getVectorIterator(); + + @Override + public String toString(int doc) throws IOException { + return valueSource.description() + strVal(doc); + } + + @Override + public boolean exists(int doc) throws IOException { + if (doc < lastDocID) { + throw new IllegalArgumentException( + "docs were sent out-of-order: lastDocID=" + lastDocID + " vs docID=" + doc); + } + + lastDocID = doc; + + int curDocID = getVectorIterator().docID(); + if (doc > curDocID) { + curDocID = getVectorIterator().advance(doc); + } + return doc == curDocID; + } +} diff --git a/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/VectorSimilarityFunction.java b/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/VectorSimilarityFunction.java new file mode 100644 index 000000000000..9ba2d359a568 --- /dev/null +++ b/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/VectorSimilarityFunction.java @@ -0,0 +1,96 @@ +/* + * 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.queries.function.valuesource; + +import java.io.IOException; +import java.util.Map; +import java.util.Objects; +import org.apache.lucene.index.LeafReaderContext; +import org.apache.lucene.queries.function.FunctionValues; +import org.apache.lucene.queries.function.ValueSource; + +/** VectorSimilarityFunction returns a similarity function between two knn vectors. */ +public abstract class VectorSimilarityFunction extends ValueSource { + + protected final org.apache.lucene.index.VectorSimilarityFunction similarityFunction; + protected final ValueSource vector1; + protected final ValueSource vector2; + + public VectorSimilarityFunction( + org.apache.lucene.index.VectorSimilarityFunction similarityFunction, + ValueSource vector1, + ValueSource vector2) { + + this.similarityFunction = similarityFunction; + this.vector1 = vector1; + this.vector2 = vector2; + } + + @Override + public FunctionValues getValues(Map context, LeafReaderContext readerContext) + throws IOException { + + final FunctionValues vector1Vals = vector1.getValues(context, readerContext); + final FunctionValues vector2Vals = vector2.getValues(context, readerContext); + return new FunctionValues() { + @Override + public float floatVal(int doc) throws IOException { + return func(doc, vector1Vals, vector2Vals); + } + + @Override + public String strVal(int doc) throws IOException { + return Float.toString(floatVal(doc)); + } + + @Override + public boolean exists(int doc) throws IOException { + return MultiFunction.allExists(doc, vector1Vals, vector2Vals); + } + + @Override + public String toString(int doc) throws IOException { + return description() + " = " + strVal(doc); + } + }; + } + + protected abstract float func(int doc, FunctionValues f1, FunctionValues f2) throws IOException; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + return Objects.equals(vector1, ((VectorSimilarityFunction) o).vector1) + && Objects.equals(vector2, ((VectorSimilarityFunction) o).vector2); + } + + @Override + public int hashCode() { + return Objects.hash(similarityFunction, vector1, vector2); + } + + @Override + public String description() { + return similarityFunction.name() + + "(" + + vector1.description() + + ", " + + vector2.description() + + ")"; + } +} diff --git a/lucene/queries/src/java/org/apache/lucene/queries/mlt/MoreLikeThisQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/mlt/MoreLikeThisQuery.java index 7ba1bb00b5ee..159d30c8e547 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/mlt/MoreLikeThisQuery.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/mlt/MoreLikeThisQuery.java @@ -22,9 +22,9 @@ import java.util.Objects; import java.util.Set; import org.apache.lucene.analysis.Analyzer; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.BooleanQuery; +import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.QueryVisitor; @@ -57,8 +57,8 @@ public MoreLikeThisQuery( } @Override - public Query rewrite(IndexReader reader) throws IOException { - MoreLikeThis mlt = new MoreLikeThis(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + MoreLikeThis mlt = new MoreLikeThis(indexSearcher.getIndexReader()); mlt.setFieldNames(moreLikeFields); mlt.setAnalyzer(analyzer); diff --git a/lucene/queries/src/java/org/apache/lucene/queries/payloads/PayloadScoreQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/payloads/PayloadScoreQuery.java index a782901f9328..d4dd52b46205 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/payloads/PayloadScoreQuery.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/payloads/PayloadScoreQuery.java @@ -19,7 +19,6 @@ import java.io.IOException; import java.util.Map; import java.util.Objects; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.PostingsEnum; import org.apache.lucene.index.Term; @@ -83,12 +82,12 @@ public String getField() { } @Override - public Query rewrite(IndexReader reader) throws IOException { - Query matchRewritten = wrappedQuery.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + Query matchRewritten = wrappedQuery.rewrite(indexSearcher); if (wrappedQuery != matchRewritten && matchRewritten instanceof SpanQuery) { return new PayloadScoreQuery((SpanQuery) matchRewritten, function, decoder, includeSpanScore); } - return super.rewrite(reader); + return super.rewrite(indexSearcher); } @Override diff --git a/lucene/queries/src/java/org/apache/lucene/queries/payloads/SpanPayloadCheckQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/payloads/SpanPayloadCheckQuery.java index 1d3c13ed9cd5..ef04a8dccd08 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/payloads/SpanPayloadCheckQuery.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/payloads/SpanPayloadCheckQuery.java @@ -20,7 +20,6 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.PostingsEnum; import org.apache.lucene.index.Term; @@ -116,13 +115,13 @@ public SpanWeight createWeight(IndexSearcher searcher, ScoreMode scoreMode, floa } @Override - public Query rewrite(IndexReader reader) throws IOException { - Query matchRewritten = match.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + Query matchRewritten = match.rewrite(indexSearcher); if (match != matchRewritten && matchRewritten instanceof SpanQuery) { return new SpanPayloadCheckQuery( (SpanQuery) matchRewritten, payloadToMatch, payloadType, operation); } - return super.rewrite(reader); + return super.rewrite(indexSearcher); } @Override diff --git a/lucene/queries/src/java/org/apache/lucene/queries/spans/FieldMaskingSpanQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/spans/FieldMaskingSpanQuery.java index 500f9aad456f..038a2e3742de 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/spans/FieldMaskingSpanQuery.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/spans/FieldMaskingSpanQuery.java @@ -18,7 +18,6 @@ import java.io.IOException; import java.util.Objects; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; @@ -93,13 +92,13 @@ public SpanWeight createWeight(IndexSearcher searcher, ScoreMode scoreMode, floa } @Override - public Query rewrite(IndexReader reader) throws IOException { - SpanQuery rewritten = (SpanQuery) maskedQuery.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + SpanQuery rewritten = (SpanQuery) maskedQuery.rewrite(indexSearcher); if (rewritten != maskedQuery) { return new FieldMaskingSpanQuery(rewritten, field); } - return super.rewrite(reader); + return super.rewrite(indexSearcher); } @Override diff --git a/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanContainQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanContainQuery.java index 680ceea0f789..99412f964065 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanContainQuery.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanContainQuery.java @@ -20,7 +20,6 @@ import java.util.ArrayList; import java.util.Map; import java.util.Objects; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.Term; import org.apache.lucene.index.TermStates; @@ -109,9 +108,9 @@ String toString(String field, String name) { } @Override - public Query rewrite(IndexReader reader) throws IOException { - SpanQuery rewrittenBig = (SpanQuery) big.rewrite(reader); - SpanQuery rewrittenLittle = (SpanQuery) little.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + SpanQuery rewrittenBig = (SpanQuery) big.rewrite(indexSearcher); + SpanQuery rewrittenLittle = (SpanQuery) little.rewrite(indexSearcher); if (big != rewrittenBig || little != rewrittenLittle) { try { SpanContainQuery clone = (SpanContainQuery) super.clone(); @@ -122,7 +121,7 @@ public Query rewrite(IndexReader reader) throws IOException { throw new AssertionError(e); } } - return super.rewrite(reader); + return super.rewrite(indexSearcher); } @Override diff --git a/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanMultiTermQueryWrapper.java b/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanMultiTermQueryWrapper.java index aa36368270ed..882e6c96fb3d 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanMultiTermQueryWrapper.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanMultiTermQueryWrapper.java @@ -117,8 +117,8 @@ public String toString(String field) { } @Override - public Query rewrite(IndexReader reader) throws IOException { - return rewriteMethod.rewrite(reader, query); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + return rewriteMethod.rewrite(indexSearcher.getIndexReader(), query); } @Override diff --git a/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanNearQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanNearQuery.java index b3f9f8e357bc..00318e4bae64 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanNearQuery.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanNearQuery.java @@ -23,7 +23,6 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.Term; import org.apache.lucene.index.TermStates; @@ -242,12 +241,12 @@ public boolean isCacheable(LeafReaderContext ctx) { } @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { boolean actuallyRewritten = false; List rewrittenClauses = new ArrayList<>(); for (int i = 0; i < clauses.size(); i++) { SpanQuery c = clauses.get(i); - SpanQuery query = (SpanQuery) c.rewrite(reader); + SpanQuery query = (SpanQuery) c.rewrite(indexSearcher); actuallyRewritten |= query != c; rewrittenClauses.add(query); } @@ -260,7 +259,7 @@ public Query rewrite(IndexReader reader) throws IOException { throw new AssertionError(e); } } - return super.rewrite(reader); + return super.rewrite(indexSearcher); } @Override diff --git a/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanNotQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanNotQuery.java index fc2f334a4bae..aded21f5f7cf 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanNotQuery.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanNotQuery.java @@ -19,7 +19,6 @@ import java.io.IOException; import java.util.Map; import java.util.Objects; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.Term; import org.apache.lucene.index.TermStates; @@ -224,13 +223,13 @@ public boolean isCacheable(LeafReaderContext ctx) { } @Override - public Query rewrite(IndexReader reader) throws IOException { - SpanQuery rewrittenInclude = (SpanQuery) include.rewrite(reader); - SpanQuery rewrittenExclude = (SpanQuery) exclude.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + SpanQuery rewrittenInclude = (SpanQuery) include.rewrite(indexSearcher); + SpanQuery rewrittenExclude = (SpanQuery) exclude.rewrite(indexSearcher); if (rewrittenInclude != include || rewrittenExclude != exclude) { return new SpanNotQuery(rewrittenInclude, rewrittenExclude, pre, post); } - return super.rewrite(reader); + return super.rewrite(indexSearcher); } @Override diff --git a/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanOrQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanOrQuery.java index 2b8e1856774a..46b14aef92dd 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanOrQuery.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanOrQuery.java @@ -21,7 +21,6 @@ import java.util.Iterator; import java.util.List; import java.util.Map; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.Term; import org.apache.lucene.index.TermStates; @@ -67,19 +66,19 @@ public String getField() { } @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { SpanOrQuery rewritten = new SpanOrQuery(); boolean actuallyRewritten = false; for (int i = 0; i < clauses.size(); i++) { SpanQuery c = clauses.get(i); - SpanQuery query = (SpanQuery) c.rewrite(reader); + SpanQuery query = (SpanQuery) c.rewrite(indexSearcher); actuallyRewritten |= query != c; rewritten.addClause(query); } if (actuallyRewritten) { return rewritten; } - return super.rewrite(reader); + return super.rewrite(indexSearcher); } @Override diff --git a/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanPositionCheckQuery.java b/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanPositionCheckQuery.java index 0227a13f3ab4..a83969f3fb5e 100644 --- a/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanPositionCheckQuery.java +++ b/lucene/queries/src/java/org/apache/lucene/queries/spans/SpanPositionCheckQuery.java @@ -19,7 +19,6 @@ import java.io.IOException; import java.util.Map; import java.util.Objects; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.Term; import org.apache.lucene.index.TermStates; @@ -113,8 +112,8 @@ protected AcceptStatus accept(Spans candidate) throws IOException { } @Override - public Query rewrite(IndexReader reader) throws IOException { - SpanQuery rewritten = (SpanQuery) match.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + SpanQuery rewritten = (SpanQuery) match.rewrite(indexSearcher); if (rewritten != match) { try { SpanPositionCheckQuery clone = (SpanPositionCheckQuery) this.clone(); @@ -125,7 +124,7 @@ public Query rewrite(IndexReader reader) throws IOException { } } - return super.rewrite(reader); + return super.rewrite(indexSearcher); } @Override diff --git a/lucene/queries/src/test/org/apache/lucene/queries/function/TestKnnVectorSimilarityFunctions.java b/lucene/queries/src/test/org/apache/lucene/queries/function/TestKnnVectorSimilarityFunctions.java new file mode 100644 index 000000000000..12144b252ba0 --- /dev/null +++ b/lucene/queries/src/test/org/apache/lucene/queries/function/TestKnnVectorSimilarityFunctions.java @@ -0,0 +1,260 @@ +/* + * 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.queries.function; + +import java.util.List; +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.document.Document; +import org.apache.lucene.document.Field; +import org.apache.lucene.document.KnnByteVectorField; +import org.apache.lucene.document.KnnFloatVectorField; +import org.apache.lucene.document.SortedDocValuesField; +import org.apache.lucene.document.StringField; +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.IndexWriterConfig; +import org.apache.lucene.index.VectorSimilarityFunction; +import org.apache.lucene.queries.function.valuesource.ByteKnnVectorFieldSource; +import org.apache.lucene.queries.function.valuesource.ByteVectorSimilarityFunction; +import org.apache.lucene.queries.function.valuesource.ConstKnnByteVectorValueSource; +import org.apache.lucene.queries.function.valuesource.ConstKnnFloatValueSource; +import org.apache.lucene.queries.function.valuesource.FloatKnnVectorFieldSource; +import org.apache.lucene.queries.function.valuesource.FloatVectorSimilarityFunction; +import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.Query; +import org.apache.lucene.search.ScoreDoc; +import org.apache.lucene.search.Sort; +import org.apache.lucene.search.SortField; +import org.apache.lucene.search.TopDocs; +import org.apache.lucene.store.Directory; +import org.apache.lucene.tests.analysis.MockAnalyzer; +import org.apache.lucene.tests.index.RandomIndexWriter; +import org.apache.lucene.tests.search.CheckHits; +import org.apache.lucene.tests.util.LuceneTestCase; +import org.apache.lucene.util.BytesRef; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +public class TestKnnVectorSimilarityFunctions extends LuceneTestCase { + static Directory dir; + static Analyzer analyzer; + static IndexReader reader; + static IndexSearcher searcher; + static final List documents = List.of("1", "2"); + + @BeforeClass + public static void beforeClass() throws Exception { + dir = newDirectory(); + analyzer = new MockAnalyzer(random()); + IndexWriterConfig iwConfig = newIndexWriterConfig(analyzer); + iwConfig.setMergePolicy(newLogMergePolicy()); + RandomIndexWriter iw = new RandomIndexWriter(random(), dir, iwConfig); + + Document document = new Document(); + document.add(new StringField("id", "1", Field.Store.NO)); + document.add(new SortedDocValuesField("id", new BytesRef("1"))); + document.add(new KnnFloatVectorField("knnFloatField1", new float[] {1.f, 2.f, 3.f})); + document.add(new KnnFloatVectorField("knnFloatField2", new float[] {5.2f, 3.2f, 3.1f})); + + // add only to the first document + document.add(new KnnFloatVectorField("knnFloatField3", new float[] {1.0f, 1.0f, 1.0f})); + document.add(new KnnByteVectorField("knnByteField3", new byte[] {1, 1, 1})); + + document.add(new KnnByteVectorField("knnByteField1", new byte[] {1, 2, 3})); + document.add(new KnnByteVectorField("knnByteField2", new byte[] {4, 2, 3})); + iw.addDocument(document); + + Document document2 = new Document(); + document2.add(new StringField("id", "2", Field.Store.NO)); + document2.add(new SortedDocValuesField("id", new BytesRef("2"))); + document2.add(new KnnFloatVectorField("knnFloatField1", new float[] {1.f, 2.f, 3.f})); + document2.add(new KnnFloatVectorField("knnFloatField2", new float[] {5.2f, 3.2f, 3.1f})); + + document2.add(new KnnByteVectorField("knnByteField1", new byte[] {1, 2, 3})); + document2.add(new KnnByteVectorField("knnByteField2", new byte[] {4, 2, 3})); + iw.addDocument(document2); + + reader = iw.getReader(); + searcher = newSearcher(reader); + iw.close(); + } + + @AfterClass + public static void afterClass() throws Exception { + searcher = null; + reader.close(); + reader = null; + dir.close(); + dir = null; + analyzer.close(); + analyzer = null; + } + + @Test + public void vectorSimilarity_floatConstantVectors_shouldReturnFloatSimilarity() throws Exception { + var v1 = new ConstKnnFloatValueSource(new float[] {1, 2, 3}); + var v2 = new ConstKnnFloatValueSource(new float[] {5, 4, 1}); + assertHits( + new FunctionQuery( + new FloatVectorSimilarityFunction(VectorSimilarityFunction.EUCLIDEAN, v1, v2)), + new float[] {0.04f, 0.04f}); + } + + @Test + public void vectorSimilarity_byteConstantVectors_shouldReturnFloatSimilarity() throws Exception { + var v1 = new ConstKnnByteVectorValueSource(new byte[] {1, 2, 3}); + var v2 = new ConstKnnByteVectorValueSource(new byte[] {2, 5, 6}); + assertHits( + new FunctionQuery( + new ByteVectorSimilarityFunction(VectorSimilarityFunction.EUCLIDEAN, v1, v2)), + new float[] {0.05f, 0.05f}); + } + + @Test + public void vectorSimilarity_floatFieldVectors_shouldReturnFloatSimilarity() throws Exception { + var v1 = new FloatKnnVectorFieldSource("knnFloatField1"); + var v2 = new FloatKnnVectorFieldSource("knnFloatField2"); + assertHits( + new FunctionQuery( + new FloatVectorSimilarityFunction(VectorSimilarityFunction.EUCLIDEAN, v1, v2)), + new float[] {0.049776014f, 0.049776014f}); + } + + @Test + public void vectorSimilarity_byteFieldVectors_shouldReturnFloatSimilarity() throws Exception { + var v1 = new ByteKnnVectorFieldSource("knnByteField1"); + var v2 = new ByteKnnVectorFieldSource("knnByteField2"); + assertHits( + new FunctionQuery( + new ByteVectorSimilarityFunction(VectorSimilarityFunction.EUCLIDEAN, v1, v2)), + new float[] {0.1f, 0.1f}); + } + + @Test + public void vectorSimilarity_FloatConstAndFloatFieldVectors_shouldReturnFloatSimilarity() + throws Exception { + var v1 = new ConstKnnFloatValueSource(new float[] {1, 2, 4}); + var v2 = new FloatKnnVectorFieldSource("knnFloatField1"); + assertHits( + new FunctionQuery( + new FloatVectorSimilarityFunction(VectorSimilarityFunction.EUCLIDEAN, v1, v2)), + new float[] {0.5f, 0.5f}); + } + + @Test + public void vectorSimilarity_ByteConstAndByteFieldVectors_shouldReturnFloatSimilarity() + throws Exception { + var v1 = new ConstKnnByteVectorValueSource(new byte[] {1, 2, 4}); + var v2 = new ByteKnnVectorFieldSource("knnByteField1"); + assertHits( + new FunctionQuery( + new ByteVectorSimilarityFunction(VectorSimilarityFunction.EUCLIDEAN, v1, v2)), + new float[] {0.5f, 0.5f}); + } + + @Test + public void vectorSimilarity_missingFloatVectorField_shouldReturnZero() throws Exception { + var v1 = new ConstKnnFloatValueSource(new float[] {2.f, 1.f, 1.f}); + var v2 = new FloatKnnVectorFieldSource("knnFloatField3"); + assertHits( + new FunctionQuery( + new FloatVectorSimilarityFunction(VectorSimilarityFunction.EUCLIDEAN, v1, v2)), + new float[] {0.5f, 0.f}); + } + + @Test + public void vectorSimilarity_missingByteVectorField_shouldReturnZero() throws Exception { + var v1 = new ConstKnnByteVectorValueSource(new byte[] {2, 1, 1}); + var v2 = new ByteKnnVectorFieldSource("knnByteField3"); + assertHits( + new FunctionQuery( + new ByteVectorSimilarityFunction(VectorSimilarityFunction.EUCLIDEAN, v1, v2)), + new float[] {0.5f, 0.f}); + } + + @Test + public void vectorSimilarity_twoVectorsWithDifferentDimensions_shouldRaiseException() { + ValueSource v1 = new ConstKnnByteVectorValueSource(new byte[] {1, 2, 3, 4}); + ValueSource v2 = new ByteKnnVectorFieldSource("knnByteField1"); + ByteVectorSimilarityFunction byteDenseVectorSimilarityFunction = + new ByteVectorSimilarityFunction(VectorSimilarityFunction.EUCLIDEAN, v1, v2); + assertThrows( + AssertionError.class, + () -> searcher.search(new FunctionQuery(byteDenseVectorSimilarityFunction), 10)); + + v1 = new ConstKnnFloatValueSource(new float[] {1.f, 2.f}); + v2 = new FloatKnnVectorFieldSource("knnFloatField1"); + FloatVectorSimilarityFunction floatDenseVectorSimilarityFunction = + new FloatVectorSimilarityFunction(VectorSimilarityFunction.EUCLIDEAN, v1, v2); + assertThrows( + AssertionError.class, + () -> searcher.search(new FunctionQuery(floatDenseVectorSimilarityFunction), 10)); + } + + @Test + public void vectorSimilarity_byteAndFloatVectors_shouldRaiseException() { + var v1 = new ConstKnnByteVectorValueSource(new byte[] {1, 2, 3}); + ValueSource v2 = new ByteKnnVectorFieldSource("knnByteField1"); + FloatVectorSimilarityFunction floatDenseVectorSimilarityFunction = + new FloatVectorSimilarityFunction(VectorSimilarityFunction.EUCLIDEAN, v1, v2); + assertThrows( + UnsupportedOperationException.class, + () -> searcher.search(new FunctionQuery(floatDenseVectorSimilarityFunction), 10)); + + v1 = new ConstKnnByteVectorValueSource(new byte[] {1, 2, 3}); + v2 = new FloatKnnVectorFieldSource("knnFloatField1"); + ByteVectorSimilarityFunction byteDenseVectorSimilarityFunction = + new ByteVectorSimilarityFunction(VectorSimilarityFunction.EUCLIDEAN, v1, v2); + assertThrows( + UnsupportedOperationException.class, + () -> searcher.search(new FunctionQuery(byteDenseVectorSimilarityFunction), 10)); + } + + @Test + public void vectorSimilarity_wrongFieldType_shouldRaiseException() { + ValueSource v1 = new ByteKnnVectorFieldSource("knnByteField1"); + ValueSource v2 = new ByteKnnVectorFieldSource("knnFloatField2"); + ByteVectorSimilarityFunction byteDenseVectorSimilarityFunction = + new ByteVectorSimilarityFunction(VectorSimilarityFunction.EUCLIDEAN, v1, v2); + + assertThrows( + IllegalArgumentException.class, + () -> searcher.search(new FunctionQuery(byteDenseVectorSimilarityFunction), 10)); + + v1 = new FloatKnnVectorFieldSource("knnByteField1"); + v2 = new FloatKnnVectorFieldSource("knnFloatField2"); + FloatVectorSimilarityFunction floatVectorSimilarityFunction = + new FloatVectorSimilarityFunction(VectorSimilarityFunction.EUCLIDEAN, v1, v2); + + assertThrows( + IllegalArgumentException.class, + () -> searcher.search(new FunctionQuery(floatVectorSimilarityFunction), 10)); + } + + private static void assertHits(Query q, float[] scores) throws Exception { + ScoreDoc[] expected = new ScoreDoc[scores.length]; + int[] expectedDocs = new int[scores.length]; + for (int i = 0; i < expected.length; i++) { + expectedDocs[i] = i; + expected[i] = new ScoreDoc(i, scores[i]); + } + TopDocs docs = + searcher.search( + q, documents.size(), new Sort(new SortField("id", SortField.Type.STRING)), true); + CheckHits.checkHitsQuery(q, expected, docs.scoreDocs, expectedDocs); + } +} diff --git a/lucene/queries/src/test/org/apache/lucene/queries/function/TestValueSources.java b/lucene/queries/src/test/org/apache/lucene/queries/function/TestValueSources.java index 93bed6fe9f5b..48a84c105f22 100644 --- a/lucene/queries/src/test/org/apache/lucene/queries/function/TestValueSources.java +++ b/lucene/queries/src/test/org/apache/lucene/queries/function/TestValueSources.java @@ -781,8 +781,8 @@ public float getMaxScore(int upTo) throws IOException { } @Override - public Query rewrite(IndexReader reader) throws IOException { - var rewrite = in.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + var rewrite = in.rewrite(indexSearcher); return rewrite == in ? this : new AssertScoreComputedOnceQuery(rewrite); } diff --git a/lucene/queries/src/test/org/apache/lucene/queries/spans/AssertingSpanQuery.java b/lucene/queries/src/test/org/apache/lucene/queries/spans/AssertingSpanQuery.java index f22a70a03023..8eab12aa7d11 100644 --- a/lucene/queries/src/test/org/apache/lucene/queries/spans/AssertingSpanQuery.java +++ b/lucene/queries/src/test/org/apache/lucene/queries/spans/AssertingSpanQuery.java @@ -18,7 +18,6 @@ import java.io.IOException; import java.util.Objects; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.QueryVisitor; @@ -50,10 +49,10 @@ public SpanWeight createWeight(IndexSearcher searcher, ScoreMode scoreMode, floa } @Override - public Query rewrite(IndexReader reader) throws IOException { - Query q = in.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + Query q = in.rewrite(indexSearcher); if (q == in) { - return super.rewrite(reader); + return super.rewrite(indexSearcher); } else if (q instanceof SpanQuery) { return new AssertingSpanQuery((SpanQuery) q); } else { diff --git a/lucene/queries/src/test/org/apache/lucene/queries/spans/TestFieldMaskingSpanQuery.java b/lucene/queries/src/test/org/apache/lucene/queries/spans/TestFieldMaskingSpanQuery.java index 567bfdf711ee..9c98a0025829 100644 --- a/lucene/queries/src/test/org/apache/lucene/queries/spans/TestFieldMaskingSpanQuery.java +++ b/lucene/queries/src/test/org/apache/lucene/queries/spans/TestFieldMaskingSpanQuery.java @@ -164,7 +164,7 @@ public void testRewrite1() throws Exception { new FieldMaskingSpanQuery( new SpanTermQuery(new Term("last", "sally")) { @Override - public Query rewrite(IndexReader reader) { + public Query rewrite(IndexSearcher indexSearcher) { return new SpanOrQuery( new SpanTermQuery(new Term("first", "sally")), new SpanTermQuery(new Term("first", "james"))); diff --git a/lucene/queryparser/src/java/org/apache/lucene/queryparser/complexPhrase/ComplexPhraseQueryParser.java b/lucene/queryparser/src/java/org/apache/lucene/queryparser/complexPhrase/ComplexPhraseQueryParser.java index 4dad705b876a..339e60a14bd6 100644 --- a/lucene/queryparser/src/java/org/apache/lucene/queryparser/complexPhrase/ComplexPhraseQueryParser.java +++ b/lucene/queryparser/src/java/org/apache/lucene/queryparser/complexPhrase/ComplexPhraseQueryParser.java @@ -22,7 +22,6 @@ import java.util.List; import java.util.Objects; import org.apache.lucene.analysis.Analyzer; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.Term; import org.apache.lucene.queries.spans.SpanNearQuery; import org.apache.lucene.queries.spans.SpanNotQuery; @@ -256,7 +255,7 @@ public void visit(QueryVisitor visitor) { } @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { final Query contents = this.contents[0]; // ArrayList spanClauses = new ArrayList(); if (contents instanceof TermQuery @@ -284,7 +283,7 @@ public Query rewrite(IndexReader reader) throws IOException { // HashSet bclauseterms=new HashSet(); Query qc = clause.getQuery(); // Rewrite this clause e.g one* becomes (one OR onerous) - qc = new IndexSearcher(reader).rewrite(qc); + qc = indexSearcher.rewrite(qc); if (clause.getOccur().equals(BooleanClause.Occur.MUST_NOT)) { numNegatives++; } diff --git a/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/DistanceRewriteQuery.java b/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/DistanceRewriteQuery.java index d739bc022e67..7186aa3cf244 100644 --- a/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/DistanceRewriteQuery.java +++ b/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/DistanceRewriteQuery.java @@ -17,7 +17,7 @@ package org.apache.lucene.queryparser.surround.query; import java.io.IOException; -import org.apache.lucene.index.IndexReader; +import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.QueryVisitor; @@ -28,8 +28,8 @@ class DistanceRewriteQuery extends RewriteQuery { } @Override - public Query rewrite(IndexReader reader) throws IOException { - return srndQuery.getSpanNearQuery(reader, fieldName, qf); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + return srndQuery.getSpanNearQuery(indexSearcher.getIndexReader(), fieldName, qf); } @Override diff --git a/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/RewriteQuery.java b/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/RewriteQuery.java index 69005e6dd00c..533cf72ce023 100644 --- a/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/RewriteQuery.java +++ b/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/RewriteQuery.java @@ -18,7 +18,7 @@ import java.io.IOException; import java.util.Objects; -import org.apache.lucene.index.IndexReader; +import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; abstract class RewriteQuery extends Query { @@ -33,7 +33,7 @@ abstract class RewriteQuery extends Query { } @Override - public abstract Query rewrite(IndexReader reader) throws IOException; + public abstract Query rewrite(IndexSearcher indexSearcher) throws IOException; @Override public String toString(String field) { diff --git a/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/SimpleTermRewriteQuery.java b/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/SimpleTermRewriteQuery.java index 22f1118beb48..4371e5f224fd 100644 --- a/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/SimpleTermRewriteQuery.java +++ b/lucene/queryparser/src/java/org/apache/lucene/queryparser/surround/query/SimpleTermRewriteQuery.java @@ -19,9 +19,9 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.Term; import org.apache.lucene.search.BooleanClause; +import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.QueryVisitor; @@ -33,10 +33,10 @@ class SimpleTermRewriteQuery extends RewriteQuery { } @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { final List luceneSubQueries = new ArrayList<>(); srndQuery.visitMatchingTerms( - reader, + indexSearcher.getIndexReader(), fieldName, new SimpleTerm.MatchingTermVisitor() { @Override diff --git a/lucene/queryparser/src/test/org/apache/lucene/queryparser/xml/TestCoreParser.java b/lucene/queryparser/src/test/org/apache/lucene/queryparser/xml/TestCoreParser.java index ae306da9afc3..102360fae87a 100644 --- a/lucene/queryparser/src/test/org/apache/lucene/queryparser/xml/TestCoreParser.java +++ b/lucene/queryparser/src/test/org/apache/lucene/queryparser/xml/TestCoreParser.java @@ -316,7 +316,7 @@ private Query implParse(String xmlFileName, boolean span) throws ParserException } protected Query rewrite(Query q) throws IOException { - return q.rewrite(reader()); + return q.rewrite(searcher()); } protected void dumpResults(String qType, Query q, int numDocs) throws IOException { diff --git a/lucene/sandbox/src/java/org/apache/lucene/sandbox/queries/FuzzyLikeThisQuery.java b/lucene/sandbox/src/java/org/apache/lucene/sandbox/queries/FuzzyLikeThisQuery.java index 6193d27a99ff..ab4cbb05fc99 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/sandbox/queries/FuzzyLikeThisQuery.java +++ b/lucene/sandbox/src/java/org/apache/lucene/sandbox/queries/FuzzyLikeThisQuery.java @@ -38,6 +38,7 @@ import org.apache.lucene.search.BoostQuery; import org.apache.lucene.search.ConstantScoreQuery; import org.apache.lucene.search.FuzzyTermsEnum; +import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.QueryVisitor; import org.apache.lucene.search.TermQuery; @@ -282,7 +283,8 @@ public void visit(QueryVisitor visitor) { } @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + IndexReader reader = indexSearcher.getIndexReader(); ScoreTermQueue q = new ScoreTermQueue(maxNumTerms); // load up the list of possible terms for (FieldVals f : fieldVals) { diff --git a/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/CombinedFieldQuery.java b/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/CombinedFieldQuery.java index 3196f9a6d997..08bb24a846cf 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/CombinedFieldQuery.java +++ b/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/CombinedFieldQuery.java @@ -253,7 +253,7 @@ public long ramBytesUsed() { } @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { if (terms.length == 0 || fieldAndWeights.isEmpty()) { return new BooleanQuery.Builder().build(); } diff --git a/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/CoveringQuery.java b/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/CoveringQuery.java index 69e5bd69f834..5a493a00c1a5 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/CoveringQuery.java +++ b/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/CoveringQuery.java @@ -22,7 +22,6 @@ import java.util.List; import java.util.Objects; import java.util.stream.Collectors; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.BooleanQuery; @@ -125,7 +124,7 @@ public long ramBytesUsed() { } @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { if (minimumNumberMatch instanceof LongValuesSource.ConstantLongValuesSource) { final long constantMin = ((LongValuesSource.ConstantLongValuesSource) minimumNumberMatch).getValue(); @@ -136,7 +135,7 @@ public Query rewrite(IndexReader reader) throws IOException { BooleanQuery.Builder builder = new BooleanQuery.Builder().setMinimumNumberShouldMatch((int) Math.max(constantMin, 1)); for (Query query : queries) { - Query r = query.rewrite(reader); + Query r = query.rewrite(indexSearcher); builder.add(r, BooleanClause.Occur.SHOULD); } return builder.build(); @@ -144,14 +143,14 @@ public Query rewrite(IndexReader reader) throws IOException { Multiset rewritten = new Multiset<>(); boolean actuallyRewritten = false; for (Query query : queries) { - Query r = query.rewrite(reader); + Query r = query.rewrite(indexSearcher); rewritten.add(r); actuallyRewritten |= query != r; } if (actuallyRewritten) { return new CoveringQuery(rewritten, minimumNumberMatch); } - return super.rewrite(reader); + return super.rewrite(indexSearcher); } @Override diff --git a/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/MultiRangeQuery.java b/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/MultiRangeQuery.java index 19b885dfed5a..837de213d227 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/MultiRangeQuery.java +++ b/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/MultiRangeQuery.java @@ -23,7 +23,6 @@ import java.util.Comparator; import java.util.List; import java.util.Objects; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.PointValues; @@ -169,7 +168,7 @@ public void visit(QueryVisitor visitor) { * #mergeOverlappingRanges} */ @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { if (numDims != 1) { return this; } diff --git a/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/PhraseWildcardQuery.java b/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/PhraseWildcardQuery.java index c4fc7189fe17..bbe8a4970eb2 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/PhraseWildcardQuery.java +++ b/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/PhraseWildcardQuery.java @@ -113,14 +113,14 @@ public String getField() { } @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { if (phraseTerms.isEmpty()) { return NO_MATCH_QUERY; } if (phraseTerms.size() == 1) { return phraseTerms.get(0).getQuery(); } - return super.rewrite(reader); + return super.rewrite(indexSearcher); } @Override diff --git a/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/TermAutomatonQuery.java b/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/TermAutomatonQuery.java index d06c99523bb6..7fae86711d87 100644 --- a/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/TermAutomatonQuery.java +++ b/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/TermAutomatonQuery.java @@ -23,7 +23,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexReaderContext; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.PostingsEnum; @@ -485,7 +484,7 @@ public Explanation explain(LeafReaderContext context, int doc) throws IOExceptio } @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { if (Operations.isEmpty(det)) { return new MatchNoDocsQuery(); } diff --git a/lucene/sandbox/src/test/org/apache/lucene/sandbox/queries/TestFuzzyLikeThisQuery.java b/lucene/sandbox/src/test/org/apache/lucene/sandbox/queries/TestFuzzyLikeThisQuery.java index 89506bfa7bfb..2b8fca789cb9 100644 --- a/lucene/sandbox/src/test/org/apache/lucene/sandbox/queries/TestFuzzyLikeThisQuery.java +++ b/lucene/sandbox/src/test/org/apache/lucene/sandbox/queries/TestFuzzyLikeThisQuery.java @@ -81,7 +81,7 @@ private void addDoc(RandomIndexWriter writer, String name, String id) throws IOE public void testClosestEditDistanceMatchComesFirst() throws Throwable { FuzzyLikeThisQuery flt = new FuzzyLikeThisQuery(10, analyzer); flt.addTerms("smith", "name", 2, 1); - Query q = flt.rewrite(searcher.getIndexReader()); + Query q = flt.rewrite(searcher); HashSet queryTerms = new HashSet<>(); q.visit(QueryVisitor.termCollector(queryTerms)); assertTrue("Should have variant smythe", queryTerms.contains(new Term("name", "smythe"))); @@ -98,7 +98,7 @@ public void testClosestEditDistanceMatchComesFirst() throws Throwable { public void testMultiWord() throws Throwable { FuzzyLikeThisQuery flt = new FuzzyLikeThisQuery(10, analyzer); flt.addTerms("jonathin smoth", "name", 2, 1); - Query q = flt.rewrite(searcher.getIndexReader()); + Query q = flt.rewrite(searcher); HashSet queryTerms = new HashSet<>(); q.visit(QueryVisitor.termCollector(queryTerms)); assertTrue("Should have variant jonathan", queryTerms.contains(new Term("name", "jonathan"))); @@ -116,7 +116,7 @@ public void testNonExistingField() throws Throwable { flt.addTerms("jonathin smoth", "name", 2, 1); flt.addTerms("jonathin smoth", "this field does not exist", 2, 1); // don't fail here just because the field doesn't exits - Query q = flt.rewrite(searcher.getIndexReader()); + Query q = flt.rewrite(searcher); HashSet queryTerms = new HashSet<>(); q.visit(QueryVisitor.termCollector(queryTerms)); assertTrue("Should have variant jonathan", queryTerms.contains(new Term("name", "jonathan"))); @@ -132,7 +132,7 @@ public void testNonExistingField() throws Throwable { public void testNoMatchFirstWordBug() throws Throwable { FuzzyLikeThisQuery flt = new FuzzyLikeThisQuery(10, analyzer); flt.addTerms("fernando smith", "name", 2, 1); - Query q = flt.rewrite(searcher.getIndexReader()); + Query q = flt.rewrite(searcher); HashSet queryTerms = new HashSet<>(); q.visit(QueryVisitor.termCollector(queryTerms)); assertTrue("Should have variant smith", queryTerms.contains(new Term("name", "smith"))); diff --git a/lucene/sandbox/src/test/org/apache/lucene/sandbox/search/TestCoveringQuery.java b/lucene/sandbox/src/test/org/apache/lucene/sandbox/search/TestCoveringQuery.java index 98d174f806c5..3edc18b16a0a 100644 --- a/lucene/sandbox/src/test/org/apache/lucene/sandbox/search/TestCoveringQuery.java +++ b/lucene/sandbox/src/test/org/apache/lucene/sandbox/search/TestCoveringQuery.java @@ -80,7 +80,8 @@ public void testRewrite() throws IOException { LongValuesSource vs = LongValuesSource.fromIntField("field"); assertEquals( new CoveringQuery(Collections.singleton(tq), vs), - new CoveringQuery(Collections.singleton(pq), vs).rewrite(new MultiReader())); + new CoveringQuery(Collections.singleton(pq), vs) + .rewrite(new IndexSearcher(new MultiReader()))); } public void testToString() { diff --git a/lucene/sandbox/src/test/org/apache/lucene/sandbox/search/TestMultiRangeQueries.java b/lucene/sandbox/src/test/org/apache/lucene/sandbox/search/TestMultiRangeQueries.java index b4d1e49445f9..0162fe2d3b58 100644 --- a/lucene/sandbox/src/test/org/apache/lucene/sandbox/search/TestMultiRangeQueries.java +++ b/lucene/sandbox/src/test/org/apache/lucene/sandbox/search/TestMultiRangeQueries.java @@ -806,7 +806,7 @@ public void testRandomRewrite() throws IOException { builder2.add(LongPoint.newRangeQuery("point", lower, upper), BooleanClause.Occur.SHOULD); } - MultiRangeQuery multiRangeQuery = (MultiRangeQuery) builder1.build().rewrite(reader); + MultiRangeQuery multiRangeQuery = (MultiRangeQuery) builder1.build().rewrite(searcher); BooleanQuery booleanQuery = builder2.build(); int count = searcher.search(multiRangeQuery, DummyTotalHitCountCollector.createManager()); int booleanCount = searcher.search(booleanQuery, DummyTotalHitCountCollector.createManager()); @@ -839,7 +839,7 @@ public void testOneDimensionCount() throws IOException { builder2.add(LongPoint.newRangeQuery("point", lower, upper), BooleanClause.Occur.SHOULD); } - MultiRangeQuery multiRangeQuery = (MultiRangeQuery) builder1.build().rewrite(reader); + MultiRangeQuery multiRangeQuery = (MultiRangeQuery) builder1.build().rewrite(searcher); BooleanQuery booleanQuery = builder2.build(); int count = multiRangeQuery diff --git a/lucene/sandbox/src/test/org/apache/lucene/sandbox/search/TestTermAutomatonQuery.java b/lucene/sandbox/src/test/org/apache/lucene/sandbox/search/TestTermAutomatonQuery.java index 8598d1efe9b2..3d5539d2e371 100644 --- a/lucene/sandbox/src/test/org/apache/lucene/sandbox/search/TestTermAutomatonQuery.java +++ b/lucene/sandbox/src/test/org/apache/lucene/sandbox/search/TestTermAutomatonQuery.java @@ -788,7 +788,7 @@ public void testRewriteNoMatch() throws Exception { w.addDocument(doc); IndexReader r = w.getReader(); - assertTrue(q.rewrite(r) instanceof MatchNoDocsQuery); + assertTrue(q.rewrite(newSearcher(r)) instanceof MatchNoDocsQuery); IOUtils.close(w, r, dir); } @@ -807,7 +807,7 @@ public void testRewriteTerm() throws Exception { w.addDocument(doc); IndexReader r = w.getReader(); - Query rewrite = q.rewrite(r); + Query rewrite = q.rewrite(newSearcher(r)); assertTrue(rewrite instanceof TermQuery); assertEquals(new Term("field", "foo"), ((TermQuery) rewrite).getTerm()); IOUtils.close(w, r, dir); @@ -830,7 +830,7 @@ public void testRewriteSimplePhrase() throws Exception { w.addDocument(doc); IndexReader r = w.getReader(); - Query rewrite = q.rewrite(r); + Query rewrite = q.rewrite(newSearcher(r)); assertTrue(rewrite instanceof PhraseQuery); Term[] terms = ((PhraseQuery) rewrite).getTerms(); assertEquals(new Term("field", "foo"), terms[0]); @@ -855,7 +855,7 @@ public CustomTermAutomatonQuery(String field) { } @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher searcher) { return this; } } @@ -876,7 +876,7 @@ public void testExplainNoMatchingDocument() throws Exception { IndexReader r = w.getReader(); IndexSearcher searcher = newSearcher(r); - Query rewrittenQuery = q.rewrite(r); + Query rewrittenQuery = q.rewrite(searcher); assertTrue(rewrittenQuery instanceof TermAutomatonQuery); TopDocs topDocs = searcher.search(rewrittenQuery, 10); @@ -918,7 +918,7 @@ public void testExplainMatchingDocuments() throws Exception { IndexReader r = w.getReader(); IndexSearcher searcher = newSearcher(r); - Query rewrittenQuery = q.rewrite(r); + Query rewrittenQuery = q.rewrite(searcher); assertTrue( "Rewritten query should be an instance of TermAutomatonQuery", rewrittenQuery instanceof TermAutomatonQuery); @@ -953,7 +953,7 @@ public void testRewritePhraseWithAny() throws Exception { w.addDocument(doc); IndexReader r = w.getReader(); - Query rewrite = q.rewrite(r); + Query rewrite = q.rewrite(newSearcher(r)); assertTrue(rewrite instanceof PhraseQuery); Term[] terms = ((PhraseQuery) rewrite).getTerms(); assertEquals(new Term("field", "foo"), terms[0]); @@ -982,7 +982,7 @@ public void testRewriteSimpleMultiPhrase() throws Exception { w.addDocument(doc); IndexReader r = w.getReader(); - Query rewrite = q.rewrite(r); + Query rewrite = q.rewrite(newSearcher(r)); assertTrue(rewrite instanceof MultiPhraseQuery); Term[][] terms = ((MultiPhraseQuery) rewrite).getTermArrays(); assertEquals(1, terms.length); @@ -1017,7 +1017,7 @@ public void testRewriteMultiPhraseWithAny() throws Exception { w.addDocument(doc); IndexReader r = w.getReader(); - Query rewrite = q.rewrite(r); + Query rewrite = q.rewrite(newSearcher(r)); assertTrue(rewrite instanceof MultiPhraseQuery); Term[][] terms = ((MultiPhraseQuery) rewrite).getTermArrays(); assertEquals(2, terms.length); diff --git a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/composite/CompositeVerifyQuery.java b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/composite/CompositeVerifyQuery.java index 354a0196229d..6483e4253940 100644 --- a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/composite/CompositeVerifyQuery.java +++ b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/composite/CompositeVerifyQuery.java @@ -17,7 +17,6 @@ package org.apache.lucene.spatial.composite; import java.io.IOException; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.search.ConstantScoreScorer; import org.apache.lucene.search.ConstantScoreWeight; @@ -47,12 +46,12 @@ public CompositeVerifyQuery(Query indexQuery, ShapeValuesPredicate predicateValu } @Override - public Query rewrite(IndexReader reader) throws IOException { - final Query rewritten = indexQuery.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + final Query rewritten = indexQuery.rewrite(indexSearcher); if (rewritten != indexQuery) { return new CompositeVerifyQuery(rewritten, predicateValueSource); } - return super.rewrite(reader); + return super.rewrite(indexSearcher); } @Override diff --git a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/vector/PointVectorStrategy.java b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/vector/PointVectorStrategy.java index 77055d15ae27..0442b1c7ec02 100644 --- a/lucene/spatial-extras/src/java/org/apache/lucene/spatial/vector/PointVectorStrategy.java +++ b/lucene/spatial-extras/src/java/org/apache/lucene/spatial/vector/PointVectorStrategy.java @@ -24,7 +24,6 @@ import org.apache.lucene.document.FieldType; import org.apache.lucene.document.StoredField; import org.apache.lucene.index.DocValuesType; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.BooleanQuery; @@ -253,8 +252,8 @@ private DistanceRangeQuery(Query inner, DoubleValuesSource distanceSource, doubl } @Override - public Query rewrite(IndexReader reader) throws IOException { - Query rewritten = inner.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + Query rewritten = inner.rewrite(indexSearcher); if (rewritten == inner) return this; return new DistanceRangeQuery(rewritten, distanceSource, limit); } diff --git a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/CompletionQuery.java b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/CompletionQuery.java index 577c1a886569..8db16c194a71 100644 --- a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/CompletionQuery.java +++ b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/CompletionQuery.java @@ -20,11 +20,11 @@ import static org.apache.lucene.search.suggest.document.CompletionAnalyzer.HOLE_CHARACTER; import java.io.IOException; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.Term; import org.apache.lucene.index.Terms; +import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.suggest.BitsProducer; @@ -83,11 +83,11 @@ public Term getTerm() { } @Override - public Query rewrite(IndexReader reader) throws IOException { + public Query rewrite(IndexSearcher indexSearcher) throws IOException { byte type = 0; boolean first = true; Terms terms; - for (LeafReaderContext context : reader.leaves()) { + for (LeafReaderContext context : indexSearcher.getLeafContexts()) { LeafReader leafReader = context.reader(); try { if ((terms = leafReader.terms(getField())) == null) { @@ -124,7 +124,7 @@ public Query rewrite(IndexReader reader) throws IOException { } } } - return super.rewrite(reader); + return super.rewrite(indexSearcher); } @Override diff --git a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/SuggestIndexSearcher.java b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/SuggestIndexSearcher.java index b4b97dbde29e..e46e73bb1aa9 100644 --- a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/SuggestIndexSearcher.java +++ b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/SuggestIndexSearcher.java @@ -62,7 +62,7 @@ public TopSuggestDocs suggest(CompletionQuery query, int n, boolean skipDuplicat public void suggest(CompletionQuery query, TopSuggestDocsCollector collector) throws IOException { // TODO use IndexSearcher.rewrite instead // have to implement equals() and hashCode() in CompletionQuerys and co - query = (CompletionQuery) query.rewrite(getIndexReader()); + query = (CompletionQuery) query.rewrite(this); Weight weight = query.createWeight(this, collector.scoreMode(), 1f); for (LeafReaderContext context : getIndexReader().leaves()) { BulkScorer scorer = weight.bulkScorer(context); diff --git a/lucene/suggest/src/test/org/apache/lucene/search/suggest/analyzing/TestAnalyzingSuggester.java b/lucene/suggest/src/test/org/apache/lucene/search/suggest/analyzing/TestAnalyzingSuggester.java index b5e49c5ec79b..cb14d983716f 100644 --- a/lucene/suggest/src/test/org/apache/lucene/search/suggest/analyzing/TestAnalyzingSuggester.java +++ b/lucene/suggest/src/test/org/apache/lucene/search/suggest/analyzing/TestAnalyzingSuggester.java @@ -1325,22 +1325,6 @@ static final Iterable shuffle(Input... values) { return asList; } - // TODO: we need BaseSuggesterTestCase? - public void testTooLongSuggestion() throws Exception { - Analyzer a = new MockAnalyzer(random()); - Directory tempDir = getDirectory(); - AnalyzingSuggester suggester = new AnalyzingSuggester(tempDir, "suggest", a); - String bigString = TestUtil.randomSimpleString(random(), 30000, 30000); - IllegalArgumentException ex = - expectThrows( - IllegalArgumentException.class, - () -> { - suggester.build(new InputArrayIterator(new Input[] {new Input(bigString, 7)})); - }); - assertTrue(ex.getMessage().contains("input automaton is too large")); - IOUtils.close(a, tempDir); - } - private Directory getDirectory() { return newDirectory(); } diff --git a/lucene/test-framework/src/java/org/apache/lucene/tests/analysis/BaseTokenStreamTestCase.java b/lucene/test-framework/src/java/org/apache/lucene/tests/analysis/BaseTokenStreamTestCase.java index b2ce16d80776..f9cd607ccacc 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/tests/analysis/BaseTokenStreamTestCase.java +++ b/lucene/test-framework/src/java/org/apache/lucene/tests/analysis/BaseTokenStreamTestCase.java @@ -55,6 +55,7 @@ import org.apache.lucene.document.TextField; import org.apache.lucene.index.IndexOptions; import org.apache.lucene.index.IndexableFieldType; +import org.apache.lucene.search.BoostAttribute; import org.apache.lucene.store.Directory; import org.apache.lucene.tests.index.RandomIndexWriter; import org.apache.lucene.tests.util.LuceneTestCase; @@ -154,7 +155,8 @@ public static void assertTokenStreamContents( boolean[] keywordAtts, boolean graphOffsetsAreCorrect, byte[][] payloads, - int[] flags) + int[] flags, + float[] boost) throws IOException { assertNotNull(output); CheckClearAttributesAttribute checkClearAtt = @@ -221,6 +223,12 @@ public static void assertTokenStreamContents( flagsAtt = ts.getAttribute(FlagsAttribute.class); } + BoostAttribute boostAtt = null; + if (boost != null) { + assertTrue("has no BoostAttribute", ts.hasAttribute(BoostAttribute.class)); + boostAtt = ts.getAttribute(BoostAttribute.class); + } + // Maps position to the start/end offset: final Map posToStartOffset = new HashMap<>(); final Map posToEndOffset = new HashMap<>(); @@ -243,6 +251,7 @@ public static void assertTokenStreamContents( if (payloadAtt != null) payloadAtt.setPayload(new BytesRef(new byte[] {0x00, -0x21, 0x12, -0x43, 0x24})); if (flagsAtt != null) flagsAtt.setFlags(~0); // all 1's + if (boostAtt != null) boostAtt.setBoost(-1f); checkClearAtt.getAndResetClearCalled(); // reset it, because we called clearAttribute() before assertTrue("token " + i + " does not exist", ts.incrementToken()); @@ -278,6 +287,9 @@ public static void assertTokenStreamContents( if (flagsAtt != null) { assertEquals("flagsAtt " + i + " term=" + termAtt, flags[i], flagsAtt.getFlags()); } + if (boostAtt != null) { + assertEquals("boostAtt " + i + " term=" + termAtt, boost[i], boostAtt.getBoost(), 0.001); + } if (payloads != null) { if (payloads[i] != null) { assertEquals("payloads " + i, new BytesRef(payloads[i]), payloadAtt.getPayload()); @@ -405,6 +417,7 @@ public static void assertTokenStreamContents( if (payloadAtt != null) payloadAtt.setPayload(new BytesRef(new byte[] {0x00, -0x21, 0x12, -0x43, 0x24})); if (flagsAtt != null) flagsAtt.setFlags(~0); // all 1's + if (boostAtt != null) boostAtt.setBoost(-1); checkClearAtt.getAndResetClearCalled(); // reset it, because we called clearAttribute() before @@ -426,6 +439,38 @@ public static void assertTokenStreamContents( ts.close(); } + public static void assertTokenStreamContents( + TokenStream ts, + String[] output, + int[] startOffsets, + int[] endOffsets, + String[] types, + int[] posIncrements, + int[] posLengths, + Integer finalOffset, + Integer finalPosInc, + boolean[] keywordAtts, + boolean graphOffsetsAreCorrect, + byte[][] payloads, + int[] flags) + throws IOException { + assertTokenStreamContents( + ts, + output, + startOffsets, + endOffsets, + types, + posIncrements, + posLengths, + finalOffset, + finalPosInc, + keywordAtts, + graphOffsetsAreCorrect, + payloads, + flags, + null); + } + public static void assertTokenStreamContents( TokenStream ts, String[] output, @@ -438,6 +483,33 @@ public static void assertTokenStreamContents( boolean[] keywordAtts, boolean graphOffsetsAreCorrect) throws IOException { + assertTokenStreamContents( + ts, + output, + startOffsets, + endOffsets, + types, + posIncrements, + posLengths, + finalOffset, + keywordAtts, + graphOffsetsAreCorrect, + null); + } + + public static void assertTokenStreamContents( + TokenStream ts, + String[] output, + int[] startOffsets, + int[] endOffsets, + String[] types, + int[] posIncrements, + int[] posLengths, + Integer finalOffset, + boolean[] keywordAtts, + boolean graphOffsetsAreCorrect, + float[] boost) + throws IOException { assertTokenStreamContents( ts, output, @@ -451,7 +523,8 @@ public static void assertTokenStreamContents( keywordAtts, graphOffsetsAreCorrect, null, - null); + null, + boost); } public static void assertTokenStreamContents( @@ -481,9 +554,36 @@ public static void assertTokenStreamContents( keywordAtts, graphOffsetsAreCorrect, payloads, + null, null); } + public static void assertTokenStreamContents( + TokenStream ts, + String[] output, + int[] startOffsets, + int[] endOffsets, + String[] types, + int[] posIncrements, + int[] posLengths, + Integer finalOffset, + boolean graphOffsetsAreCorrect, + float[] boost) + throws IOException { + assertTokenStreamContents( + ts, + output, + startOffsets, + endOffsets, + types, + posIncrements, + posLengths, + finalOffset, + null, + graphOffsetsAreCorrect, + boost); + } + public static void assertTokenStreamContents( TokenStream ts, String[] output, @@ -505,7 +605,8 @@ public static void assertTokenStreamContents( posLengths, finalOffset, null, - graphOffsetsAreCorrect); + graphOffsetsAreCorrect, + null); } public static void assertTokenStreamContents( @@ -522,6 +623,30 @@ public static void assertTokenStreamContents( ts, output, startOffsets, endOffsets, types, posIncrements, posLengths, finalOffset, true); } + public static void assertTokenStreamContents( + TokenStream ts, + String[] output, + int[] startOffsets, + int[] endOffsets, + String[] types, + int[] posIncrements, + int[] posLengths, + Integer finalOffset, + float[] boost) + throws IOException { + assertTokenStreamContents( + ts, + output, + startOffsets, + endOffsets, + types, + posIncrements, + posLengths, + finalOffset, + true, + boost); + } + public static void assertTokenStreamContents( TokenStream ts, String[] output, @@ -649,6 +774,21 @@ public static void assertAnalyzesTo( int[] posIncrements, int[] posLengths) throws IOException { + assertAnalyzesTo( + a, input, output, startOffsets, endOffsets, types, posIncrements, posLengths, null); + } + + public static void assertAnalyzesTo( + Analyzer a, + String input, + String[] output, + int[] startOffsets, + int[] endOffsets, + String[] types, + int[] posIncrements, + int[] posLengths, + float[] boost) + throws IOException { assertTokenStreamContents( a.tokenStream("dummy", input), output, @@ -657,7 +797,8 @@ public static void assertAnalyzesTo( types, posIncrements, posLengths, - input.length()); + input.length(), + boost); checkResetException(a, input); checkAnalysisConsistency(random(), a, true, input); } diff --git a/lucene/test-framework/src/java/org/apache/lucene/tests/index/RandomIndexWriter.java b/lucene/test-framework/src/java/org/apache/lucene/tests/index/RandomIndexWriter.java index 11cd73a2aaf5..2988957ba295 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/tests/index/RandomIndexWriter.java +++ b/lucene/test-framework/src/java/org/apache/lucene/tests/index/RandomIndexWriter.java @@ -39,6 +39,7 @@ import org.apache.lucene.internal.tests.IndexWriterAccess; import org.apache.lucene.internal.tests.TestSecrets; import org.apache.lucene.search.Query; +import org.apache.lucene.search.TermQuery; import org.apache.lucene.store.Directory; import org.apache.lucene.tests.analysis.MockAnalyzer; import org.apache.lucene.tests.util.LuceneTestCase; @@ -283,7 +284,12 @@ public long updateDocuments( w.softUpdateDocuments( delTerm, docs, new NumericDocValuesField(config.getSoftDeletesField(), 1)); } else { - seqNo = w.updateDocuments(delTerm, docs); + if (r.nextInt(10) < 3) { + // 30% chance + seqNo = w.updateDocuments(new TermQuery(delTerm), docs); + } else { + seqNo = w.updateDocuments(delTerm, docs); + } } maybeFlushOrCommit(); return seqNo; diff --git a/lucene/test-framework/src/java/org/apache/lucene/tests/search/AssertingQuery.java b/lucene/test-framework/src/java/org/apache/lucene/tests/search/AssertingQuery.java index 0947ff908bb4..d4fcb653aba1 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/tests/search/AssertingQuery.java +++ b/lucene/test-framework/src/java/org/apache/lucene/tests/search/AssertingQuery.java @@ -18,7 +18,6 @@ import java.io.IOException; import java.util.Random; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.QueryVisitor; @@ -74,10 +73,10 @@ public Query getIn() { } @Override - public Query rewrite(IndexReader reader) throws IOException { - final Query rewritten = in.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + final Query rewritten = in.rewrite(indexSearcher); if (rewritten == in) { - return super.rewrite(reader); + return super.rewrite(indexSearcher); } else { return wrap(new Random(random.nextLong()), rewritten); } diff --git a/lucene/test-framework/src/java/org/apache/lucene/tests/search/BlockScoreQueryWrapper.java b/lucene/test-framework/src/java/org/apache/lucene/tests/search/BlockScoreQueryWrapper.java index ebb5c4bd1322..5745aef757be 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/tests/search/BlockScoreQueryWrapper.java +++ b/lucene/test-framework/src/java/org/apache/lucene/tests/search/BlockScoreQueryWrapper.java @@ -19,7 +19,6 @@ import java.io.IOException; import java.util.Arrays; import java.util.Objects; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.Explanation; @@ -69,12 +68,12 @@ public int hashCode() { } @Override - public Query rewrite(IndexReader reader) throws IOException { - final Query rewritten = query.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + final Query rewritten = query.rewrite(indexSearcher); if (rewritten != query) { return new BlockScoreQueryWrapper(rewritten, blockLength); } - return super.rewrite(reader); + return super.rewrite(indexSearcher); } @Override diff --git a/lucene/test-framework/src/java/org/apache/lucene/tests/search/RandomApproximationQuery.java b/lucene/test-framework/src/java/org/apache/lucene/tests/search/RandomApproximationQuery.java index 78dc60732fb1..d58baae69361 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/tests/search/RandomApproximationQuery.java +++ b/lucene/test-framework/src/java/org/apache/lucene/tests/search/RandomApproximationQuery.java @@ -19,7 +19,6 @@ import com.carrotsearch.randomizedtesting.generators.RandomNumbers; import java.io.IOException; import java.util.Random; -import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.FilterWeight; @@ -43,12 +42,12 @@ public RandomApproximationQuery(Query query, Random random) { } @Override - public Query rewrite(IndexReader reader) throws IOException { - final Query rewritten = query.rewrite(reader); + public Query rewrite(IndexSearcher indexSearcher) throws IOException { + final Query rewritten = query.rewrite(indexSearcher); if (rewritten != query) { return new RandomApproximationQuery(rewritten, random); } - return super.rewrite(reader); + return super.rewrite(indexSearcher); } @Override diff --git a/lucene/test-framework/src/java/org/apache/lucene/tests/util/BaseBitSetTestCase.java b/lucene/test-framework/src/java/org/apache/lucene/tests/util/BaseBitSetTestCase.java index 1bb5e500a44c..cbce97d87ac7 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/tests/util/BaseBitSetTestCase.java +++ b/lucene/test-framework/src/java/org/apache/lucene/tests/util/BaseBitSetTestCase.java @@ -170,6 +170,22 @@ public void testClearRange() throws IOException { } } + /** Test the {@link BitSet#clear()} method. */ + public void testClearAll() throws IOException { + Random random = random(); + final int numBits = 1 + random.nextInt(100000); + for (float percentSet : new float[] {0, 0.01f, 0.1f, 0.5f, 0.9f, 0.99f, 1f}) { + BitSet set1 = new JavaUtilBitSet(randomSet(numBits, percentSet), numBits); + T set2 = copyOf(set1, numBits); + final int iters = atLeast(random, 10); + for (int i = 0; i < iters; ++i) { + set1.clear(); + set2.clear(); + assertEquals(set1, set2, numBits); + } + } + } + private DocIdSet randomCopy(BitSet set, int numBits) throws IOException { switch (random().nextInt(5)) { case 0: @@ -241,6 +257,11 @@ private static class JavaUtilBitSet extends BitSet { this.numBits = numBits; } + @Override + public void clear() { + bitSet.clear(); + } + @Override public void clear(int index) { bitSet.clear(index); diff --git a/lucene/test-framework/src/resources/org/apache/lucene/tests/geo/github-12352-1.geojson.gz b/lucene/test-framework/src/resources/org/apache/lucene/tests/geo/github-12352-1.geojson.gz new file mode 100644 index 0000000000000000000000000000000000000000..17a9a17393e78fc8ff83eb8c54777e05f9af2226 GIT binary patch literal 82183 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

    m(nmLEhw9R*CIO#jL-? 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 B-X;J5 literal 0 HcmV?d00001 diff --git a/lucene/test-framework/src/resources/org/apache/lucene/tests/geo/github-12352-2.geojson.gz b/lucene/test-framework/src/resources/org/apache/lucene/tests/geo/github-12352-2.geojson.gz new file mode 100644 index 0000000000000000000000000000000000000000..eec620e2b8c9c0f6d16f0788a6afb61c8e35afe7 GIT binary patch literal 111625 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ťWutmRoNlPOta)1=x-_P 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 Vt4e=O(o_Hd literal 0 HcmV?d00001