Upgrade to lucene-9.5.0-snapshot-d19c3e2e0ed (#92957)

9.5 will include several changes related to vector search. An extensive list is available at https://github.com/apache/lucene/milestone/4 .
This commit is contained in:
Luca Cavanna 2023-01-19 14:07:33 +01:00 committed by GitHub
parent 6ff081beef
commit edd7749164
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
59 changed files with 3655 additions and 2087 deletions

View file

@ -1,5 +1,5 @@
elasticsearch = 8.7.0 elasticsearch = 8.7.0
lucene = 9.4.2 lucene = 9.5.0-snapshot-d19c3e2e0ed
bundled_jdk_vendor = openjdk bundled_jdk_vendor = openjdk
bundled_jdk = 19.0.1+10@afdd2e245b014143b62ccb916125e3ce bundled_jdk = 19.0.1+10@afdd2e245b014143b62ccb916125e3ce
@ -21,12 +21,12 @@ netty = 4.1.86.Final
commons_lang3 = 3.9 commons_lang3 = 3.9
antlr4 = 4.11.1
# when updating this version, you need to ensure compatibility with: # when updating this version, you need to ensure compatibility with:
# - modules/ingest-attachment (transitive dependency, check the upstream POM) # - modules/ingest-attachment (transitive dependency, check the upstream POM)
# - distribution/tools/plugin-cli # - distribution/tools/plugin-cli
# - x-pack/plugin/security # - x-pack/plugin/security
bouncycastle=1.64 bouncycastle=1.64
# used by security and idp (need to be in sync due to cross-dependency in testing) # used by security and idp (need to be in sync due to cross-dependency in testing)
opensaml = 4.0.1 opensaml = 4.0.1

View file

@ -73,3 +73,6 @@
## GC logging ## GC logging
-Xlog:gc*,gc+age=trace,safepoint:file=@loggc@:utctime,level,pid,tags:filecount=32,filesize=64m -Xlog:gc*,gc+age=trace,safepoint:file=@loggc@:utctime,level,pid,tags:filecount=32,filesize=64m
# temporarily disable the Panama-based MMapDirectory
-Dorg.apache.lucene.store.MMapDirectory.enableMemorySegments=false

View file

@ -1,8 +1,8 @@
include::{docs-root}/shared/versions/stack/{source_branch}.asciidoc[] include::{docs-root}/shared/versions/stack/{source_branch}.asciidoc[]
:lucene_version: 9.4.2 :lucene_version: 9.5.0
:lucene_version_path: 9_4_2 :lucene_version_path: 9_5_0
:jdk: 11.0.2 :jdk: 11.0.2
:jdk_major: 11 :jdk_major: 11
:build_type: tar :build_type: tar

View file

@ -0,0 +1,5 @@
pr: 92957
summary: Upgrade to lucene-9.5.0-snapshot-d19c3e2e0ed
area: Search
type: upgrade
issues: []

View file

@ -759,26 +759,36 @@
<sha256 value="37f5216e14af2772930dff9b8734353f0a80e89ba3f33e065441de6537c5e842" origin="Generated by Gradle"/> <sha256 value="37f5216e14af2772930dff9b8734353f0a80e89ba3f33e065441de6537c5e842" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="com.ibm.icu" name="icu4j" version="61.1"> <component group="com.ibm.icu" name="icu4j" version="61.1">
<artifact name="icu4j-61.1.jar"> <artifact name="icu4j-61.1.jar">
<sha256 value="55c98eb1838b2a4bb9a07dc36bd378532d64d0cdcb7ceee914236866a7de4464" origin="Generated by Gradle"/> <sha256 value="55c98eb1838b2a4bb9a07dc36bd378532d64d0cdcb7ceee914236866a7de4464"
</artifact> origin="Generated by Gradle"/>
</component> </artifact>
<component group="com.ibm.icu" name="icu4j" version="68.2"> </component>
<artifact name="icu4j-68.2.jar"> <component group="com.ibm.icu" name="icu4j" version="68.2">
<sha256 value="9bd7bf869a44ba8aeb0cddd7e6616e88cd4795ba5bfce2230447cb0e185a646c" origin="Generated by Gradle"/> <artifact name="icu4j-68.2.jar">
</artifact> <sha256 value="9bd7bf869a44ba8aeb0cddd7e6616e88cd4795ba5bfce2230447cb0e185a646c"
</component> origin="Generated by Gradle"/>
<component group="com.jamesmurty.utils" name="java-xmlbuilder" version="0.4"> </artifact>
<artifact name="java-xmlbuilder-0.4.jar"> </component>
<sha256 value="681e53c4ffd59fa12068803b259e3a83d43f07a47c112e748a187dee179eb31f" origin="Generated by Gradle"/> <component group="com.ibm.icu" name="icu4j" version="71.1">
</artifact> <artifact name="icu4j-71.1.jar">
</component> <sha256 value="91c4f8ebf0ceb489547098fe9d5c09a65eb419caea6ed714867f5280800bcf1a"
<component group="com.jcraft" name="jsch" version="0.1.54"> origin="Generated by Gradle"/>
<artifact name="jsch-0.1.54.jar"> </artifact>
<sha256 value="92eb273a3316762478fdd4fe03a0ce1842c56f496c9c12fe1235db80450e1fdb" origin="Generated by Gradle"/> </component>
</artifact> <component group="com.jamesmurty.utils" name="java-xmlbuilder" version="0.4">
</component> <artifact name="java-xmlbuilder-0.4.jar">
<sha256 value="681e53c4ffd59fa12068803b259e3a83d43f07a47c112e748a187dee179eb31f"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.jcraft" name="jsch" version="0.1.54">
<artifact name="jsch-0.1.54.jar">
<sha256 value="92eb273a3316762478fdd4fe03a0ce1842c56f496c9c12fe1235db80450e1fdb"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.jcraft" name="jsch" version="0.1.55"> <component group="com.jcraft" name="jsch" version="0.1.55">
<artifact name="jsch-0.1.55.jar"> <artifact name="jsch-0.1.55.jar">
<sha256 value="d492b15a6d2ea3f1cc39c422c953c40c12289073dbe8360d98c0f6f9ec74fc44" origin="Generated by Gradle"/> <sha256 value="d492b15a6d2ea3f1cc39c422c953c40c12289073dbe8360d98c0f6f9ec74fc44" origin="Generated by Gradle"/>
@ -1678,49 +1688,82 @@
<sha256 value="adb1a33c07b45c39b926bdeeadf800f701be9c3d04e0deb543069e5f09856185" origin="Generated by Gradle"/> <sha256 value="adb1a33c07b45c39b926bdeeadf800f701be9c3d04e0deb543069e5f09856185" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="org.abego.treelayout" name="org.abego.treelayout.core" version="1.0.3"> <component group="org.abego.treelayout" name="org.abego.treelayout.core" version="1.0.3">
<artifact name="org.abego.treelayout.core-1.0.3.jar"> <artifact name="org.abego.treelayout.core-1.0.3.jar">
<sha256 value="fa5e31395c39c2e7d46aca0f81f72060931607b2fa41bd36038eb2cb6fb93326" origin="Generated by Gradle"/> <sha256 value="fa5e31395c39c2e7d46aca0f81f72060931607b2fa41bd36038eb2cb6fb93326"
</artifact> origin="Generated by Gradle"/>
</component> </artifact>
<component group="org.antlr" name="ST4" version="4.3"> </component>
<artifact name="ST4-4.3.jar"> <component group="org.antlr" name="ST4" version="4.3">
<sha256 value="28547dba48cfceb77b6efbfe069aebe9ed3324ae60dbd52093d13a1d636ed069" origin="Generated by Gradle"/> <artifact name="ST4-4.3.jar">
</artifact> <sha256 value="28547dba48cfceb77b6efbfe069aebe9ed3324ae60dbd52093d13a1d636ed069"
</component> origin="Generated by Gradle"/>
<component group="org.antlr" name="antlr-runtime" version="3.4"> </artifact>
<artifact name="antlr-runtime-3.4.jar"> </component>
<sha256 value="5b7cf53b7b30b034023f58030c8147c433f2bee0fe7dec8fae6bebf3708c5a63" origin="Generated by Gradle"/> <component group="org.antlr" name="ST4" version="4.3.4">
</artifact> <artifact name="ST4-4.3.4.jar">
</component> <sha256 value="f927ac384c46d749f8b5ec68972a53aed21e00313509299616edb73bfa15ff33"
<component group="org.antlr" name="antlr-runtime" version="3.5.2"> origin="Generated by Gradle"/>
<artifact name="antlr-runtime-3.5.2.jar"> </artifact>
<sha256 value="ce3fc8ecb10f39e9a3cddcbb2ce350d272d9cd3d0b1e18e6fe73c3b9389c8734" origin="Generated by Gradle"/> </component>
</artifact> <component group="org.antlr" name="antlr-runtime" version="3.4">
</component> <artifact name="antlr-runtime-3.4.jar">
<component group="org.antlr" name="antlr4" version="4.5.3"> <sha256 value="5b7cf53b7b30b034023f58030c8147c433f2bee0fe7dec8fae6bebf3708c5a63"
<artifact name="antlr4-4.5.3.jar"> origin="Generated by Gradle"/>
<sha256 value="a32de739cfdf515774e696f91aa9697d2e7731e5cb5045ca8a4b657f8b1b4fb4" origin="Generated by Gradle"/> </artifact>
</artifact> </component>
</component> <component group="org.antlr" name="antlr-runtime" version="3.5.2">
<component group="org.antlr" name="antlr4" version="4.9.2"> <artifact name="antlr-runtime-3.5.2.jar">
<artifact name="antlr4-4.9.2.jar"> <sha256 value="ce3fc8ecb10f39e9a3cddcbb2ce350d272d9cd3d0b1e18e6fe73c3b9389c8734"
<sha256 value="7d66253762da7c8c7ab6ac05da1471aeeb3cb8e92310ecfb08f939306b4c7dae" origin="Generated by Gradle"/> origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="org.antlr" name="antlr4-runtime" version="4.10.1"> <component group="org.antlr" name="antlr-runtime" version="3.5.3">
<artifact name="antlr4-runtime-4.10.1.jar"> <artifact name="antlr-runtime-3.5.3.jar">
<sha256 value="da66be0c98acfb29bc708300d05f1a3269c40f9984a4cb9251cf2ba1898d1334" origin="Generated by Gradle"/> <sha256 value="68bf9f5a33dfcb34033495c587e6236bef4e37aa6612919f5b1e843b90669fb9"
</artifact> origin="Generated by Gradle"/>
</component> </artifact>
<component group="org.antlr" name="antlr4-runtime" version="4.5.1-1"> </component>
<artifact name="antlr4-runtime-4.5.1-1.jar"> <component group="org.antlr" name="antlr4" version="4.11.1">
<sha256 value="ffca72bc2a25bb2b0c80a58cee60530a78be17da739bb6c91a8c2e3584ca099e" origin="Generated by Gradle"/> <artifact name="antlr4-4.11.1.jar">
</artifact> <sha256 value="e9686e8a663ca512afe3a2eeb6f6ad3f303abb46188991f19ebc6a0fd9c1c14f"
</component> origin="Generated by Gradle"/>
<component group="org.antlr" name="antlr4-runtime" version="4.5.3"> </artifact>
<artifact name="antlr4-runtime-4.5.3.jar"> </component>
<sha256 value="93bca08ec995caeaaf60bdf80035a0be8507fcdabd3c2618fd8c5aab4444a752" origin="Generated by Gradle"/> <component group="org.antlr" name="antlr4" version="4.5.3">
<artifact name="antlr4-4.5.3.jar">
<sha256 value="a32de739cfdf515774e696f91aa9697d2e7731e5cb5045ca8a4b657f8b1b4fb4"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.antlr" name="antlr4" version="4.9.2">
<artifact name="antlr4-4.9.2.jar">
<sha256 value="7d66253762da7c8c7ab6ac05da1471aeeb3cb8e92310ecfb08f939306b4c7dae"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.antlr" name="antlr4-runtime" version="4.10.1">
<artifact name="antlr4-runtime-4.10.1.jar">
<sha256 value="da66be0c98acfb29bc708300d05f1a3269c40f9984a4cb9251cf2ba1898d1334"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.antlr" name="antlr4-runtime" version="4.11.1">
<artifact name="antlr4-runtime-4.11.1.jar">
<sha256 value="e06c6553c1ccc14d36052ec4b0fc6f13b808cf957b5b1dc3f61bf401996ada59"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.antlr" name="antlr4-runtime" version="4.5.1-1">
<artifact name="antlr4-runtime-4.5.1-1.jar">
<sha256 value="ffca72bc2a25bb2b0c80a58cee60530a78be17da739bb6c91a8c2e3584ca099e"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.antlr" name="antlr4-runtime" version="4.5.3">
<artifact name="antlr4-runtime-4.5.3.jar">
<sha256 value="93bca08ec995caeaaf60bdf80035a0be8507fcdabd3c2618fd8c5aab4444a752"
origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="org.antlr" name="antlr4-runtime" version="4.9.2"> <component group="org.antlr" name="antlr4-runtime" version="4.9.2">
@ -2611,6 +2654,11 @@
<sha256 value="cafa2c66ac81894c860e2213c6ba71d4c5a3ae6a26be698318e7de88efdd4db5" origin="Generated by Gradle"/> <sha256 value="cafa2c66ac81894c860e2213c6ba71d4c5a3ae6a26be698318e7de88efdd4db5" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="org.apache.lucene" name="lucene-analysis-common" version="9.5.0-snapshot-d19c3e2e0ed">
<artifact name="lucene-analysis-common-9.5.0-snapshot-d19c3e2e0ed.jar">
<sha256 value="73f276384d65dc01697617112d960a0f01fcc197c4925f2144f386fcb21d9445" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.lucene" name="lucene-analysis-icu" version="9.4.1"> <component group="org.apache.lucene" name="lucene-analysis-icu" version="9.4.1">
<artifact name="lucene-analysis-icu-9.4.1.jar"> <artifact name="lucene-analysis-icu-9.4.1.jar">
<sha256 value="a5f35d7294ef475e9e3145e0a191551f5841da738212c4923b0a403a027db200" origin="Generated by Gradle"/> <sha256 value="a5f35d7294ef475e9e3145e0a191551f5841da738212c4923b0a403a027db200" origin="Generated by Gradle"/>
@ -2621,6 +2669,11 @@
<sha256 value="6fc669da198bea83f2c0616a4eb765f30b7dcb729725aa098528151bb36be9d6" origin="Generated by Gradle"/> <sha256 value="6fc669da198bea83f2c0616a4eb765f30b7dcb729725aa098528151bb36be9d6" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="org.apache.lucene" name="lucene-analysis-icu" version="9.5.0-snapshot-d19c3e2e0ed">
<artifact name="lucene-analysis-icu-9.5.0-snapshot-d19c3e2e0ed.jar">
<sha256 value="946c7756ee4320d09b5d55e7895b6285a5ad29e99c9de54d2aec620c4378fbac" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.lucene" name="lucene-analysis-kuromoji" version="9.4.1"> <component group="org.apache.lucene" name="lucene-analysis-kuromoji" version="9.4.1">
<artifact name="lucene-analysis-kuromoji-9.4.1.jar"> <artifact name="lucene-analysis-kuromoji-9.4.1.jar">
<sha256 value="daaf3c6939a9b234682d45102b8c26872f0b2d33631feefb4795a54a6dddc75a" origin="Generated by Gradle"/> <sha256 value="daaf3c6939a9b234682d45102b8c26872f0b2d33631feefb4795a54a6dddc75a" origin="Generated by Gradle"/>
@ -2631,6 +2684,11 @@
<sha256 value="13928e760951491b66e1b37f3396a0ee4b150f02a4cbe57743b68dbd0d09ab61" origin="Generated by Gradle"/> <sha256 value="13928e760951491b66e1b37f3396a0ee4b150f02a4cbe57743b68dbd0d09ab61" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="org.apache.lucene" name="lucene-analysis-kuromoji" version="9.5.0-snapshot-d19c3e2e0ed">
<artifact name="lucene-analysis-kuromoji-9.5.0-snapshot-d19c3e2e0ed.jar">
<sha256 value="0a1a38c2e357c67e3583ef8894f336b389a5a5337795b1ef698d7cb0b826d8e6" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.lucene" name="lucene-analysis-morfologik" version="9.4.1"> <component group="org.apache.lucene" name="lucene-analysis-morfologik" version="9.4.1">
<artifact name="lucene-analysis-morfologik-9.4.1.jar"> <artifact name="lucene-analysis-morfologik-9.4.1.jar">
<sha256 value="55cc0c58ef51d62ad0db64d130bbf163ec2bb9431acb898446e9039165c97f5b" origin="Generated by Gradle"/> <sha256 value="55cc0c58ef51d62ad0db64d130bbf163ec2bb9431acb898446e9039165c97f5b" origin="Generated by Gradle"/>
@ -2641,6 +2699,11 @@
<sha256 value="2835fb73f8d58ded27e9201a8d9546e0bdc5d028f5ae5f112f6f74cf71a291ee" origin="Generated by Gradle"/> <sha256 value="2835fb73f8d58ded27e9201a8d9546e0bdc5d028f5ae5f112f6f74cf71a291ee" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="org.apache.lucene" name="lucene-analysis-morfologik" version="9.5.0-snapshot-d19c3e2e0ed">
<artifact name="lucene-analysis-morfologik-9.5.0-snapshot-d19c3e2e0ed.jar">
<sha256 value="7e2cf5326302d55962944d3ba7a18b8a76b9a49d87e15c4c1904a0b4ae6afdac" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.lucene" name="lucene-analysis-nori" version="9.4.1"> <component group="org.apache.lucene" name="lucene-analysis-nori" version="9.4.1">
<artifact name="lucene-analysis-nori-9.4.1.jar"> <artifact name="lucene-analysis-nori-9.4.1.jar">
<sha256 value="f3e3119787e002606181078e2d2d28715ea80222dd82d5f34013ab11a097e786" origin="Generated by Gradle"/> <sha256 value="f3e3119787e002606181078e2d2d28715ea80222dd82d5f34013ab11a097e786" origin="Generated by Gradle"/>
@ -2651,6 +2714,11 @@
<sha256 value="316776f69a9e493c36c9a1b9b18b1f10de3914a45537e7f324784ab11d748267" origin="Generated by Gradle"/> <sha256 value="316776f69a9e493c36c9a1b9b18b1f10de3914a45537e7f324784ab11d748267" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="org.apache.lucene" name="lucene-analysis-nori" version="9.5.0-snapshot-d19c3e2e0ed">
<artifact name="lucene-analysis-nori-9.5.0-snapshot-d19c3e2e0ed.jar">
<sha256 value="4de35194eebdfb226cfe497058cec2dfd5834f7da78251bd5bc5362e0b36f807" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.lucene" name="lucene-analysis-phonetic" version="9.4.1"> <component group="org.apache.lucene" name="lucene-analysis-phonetic" version="9.4.1">
<artifact name="lucene-analysis-phonetic-9.4.1.jar"> <artifact name="lucene-analysis-phonetic-9.4.1.jar">
<sha256 value="57b21cf3c13a128d5817c369b43bb843a332ada8569bee99300b2439024daf1a" origin="Generated by Gradle"/> <sha256 value="57b21cf3c13a128d5817c369b43bb843a332ada8569bee99300b2439024daf1a" origin="Generated by Gradle"/>
@ -2661,6 +2729,11 @@
<sha256 value="30c2af3312daae2facbc43c49e4635b8f6426641d2870f7c1750ba2496c889fe" origin="Generated by Gradle"/> <sha256 value="30c2af3312daae2facbc43c49e4635b8f6426641d2870f7c1750ba2496c889fe" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="org.apache.lucene" name="lucene-analysis-phonetic" version="9.5.0-snapshot-d19c3e2e0ed">
<artifact name="lucene-analysis-phonetic-9.5.0-snapshot-d19c3e2e0ed.jar">
<sha256 value="e65ce76f0ca6dd3ff3befde0a8a04951af46e195284ee6e75eab32ad25aabce3" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.lucene" name="lucene-analysis-smartcn" version="9.4.1"> <component group="org.apache.lucene" name="lucene-analysis-smartcn" version="9.4.1">
<artifact name="lucene-analysis-smartcn-9.4.1.jar"> <artifact name="lucene-analysis-smartcn-9.4.1.jar">
<sha256 value="ff65b08a942c4e9b4050f4d4a697cb550fe04e12464af14869c09f02fc75bab5" origin="Generated by Gradle"/> <sha256 value="ff65b08a942c4e9b4050f4d4a697cb550fe04e12464af14869c09f02fc75bab5" origin="Generated by Gradle"/>
@ -2671,6 +2744,11 @@
<sha256 value="ac101ee6815499d04a29693f089b141a2dd207a063e47968475bd829caa9bcf2" origin="Generated by Gradle"/> <sha256 value="ac101ee6815499d04a29693f089b141a2dd207a063e47968475bd829caa9bcf2" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="org.apache.lucene" name="lucene-analysis-smartcn" version="9.5.0-snapshot-d19c3e2e0ed">
<artifact name="lucene-analysis-smartcn-9.5.0-snapshot-d19c3e2e0ed.jar">
<sha256 value="ca83467b4d20f00a4dbbf7c0ec35b977ed9dfc74498d563335e5a4d4c7d9474e" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.lucene" name="lucene-analysis-stempel" version="9.4.1"> <component group="org.apache.lucene" name="lucene-analysis-stempel" version="9.4.1">
<artifact name="lucene-analysis-stempel-9.4.1.jar"> <artifact name="lucene-analysis-stempel-9.4.1.jar">
<sha256 value="d32007019f35bef2f0ff47b192f4d2faac457bafa448336c905e0c1433e929e7" origin="Generated by Gradle"/> <sha256 value="d32007019f35bef2f0ff47b192f4d2faac457bafa448336c905e0c1433e929e7" origin="Generated by Gradle"/>
@ -2681,6 +2759,11 @@
<sha256 value="7b8848fa29b4506f87e03c86699feb243cd258fe3ce92f0db8201417689e530a" origin="Generated by Gradle"/> <sha256 value="7b8848fa29b4506f87e03c86699feb243cd258fe3ce92f0db8201417689e530a" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="org.apache.lucene" name="lucene-analysis-stempel" version="9.5.0-snapshot-d19c3e2e0ed">
<artifact name="lucene-analysis-stempel-9.5.0-snapshot-d19c3e2e0ed.jar">
<sha256 value="d0ebadf4fee6e727197981f2295dc043ddd47077b58624e76af9d4b84e65464b" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.lucene" name="lucene-backward-codecs" version="9.4.1"> <component group="org.apache.lucene" name="lucene-backward-codecs" version="9.4.1">
<artifact name="lucene-backward-codecs-9.4.1.jar"> <artifact name="lucene-backward-codecs-9.4.1.jar">
<sha256 value="abdbf830fae812b27ddc98d8287e60582c8f9cffd8292a064f1f9aa8ab5e0ff0" origin="Generated by Gradle"/> <sha256 value="abdbf830fae812b27ddc98d8287e60582c8f9cffd8292a064f1f9aa8ab5e0ff0" origin="Generated by Gradle"/>
@ -2691,6 +2774,11 @@
<sha256 value="8a6dc9181693d61b25ddb057cec31abdb4d6573b12b4a096b9b5739093a45c91" origin="Generated by Gradle"/> <sha256 value="8a6dc9181693d61b25ddb057cec31abdb4d6573b12b4a096b9b5739093a45c91" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="org.apache.lucene" name="lucene-backward-codecs" version="9.5.0-snapshot-d19c3e2e0ed">
<artifact name="lucene-backward-codecs-9.5.0-snapshot-d19c3e2e0ed.jar">
<sha256 value="e1ec8f11b9c83c0249eb145729921a08227bbcfe883c409a17309b5ab6a3824e" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.lucene" name="lucene-codecs" version="9.4.1"> <component group="org.apache.lucene" name="lucene-codecs" version="9.4.1">
<artifact name="lucene-codecs-9.4.1.jar"> <artifact name="lucene-codecs-9.4.1.jar">
<sha256 value="e69bcce29b43e9e09c85eb9e8a17128aa90a631c8a1b014b4efc7b8487222f4e" origin="Generated by Gradle"/> <sha256 value="e69bcce29b43e9e09c85eb9e8a17128aa90a631c8a1b014b4efc7b8487222f4e" origin="Generated by Gradle"/>
@ -2701,6 +2789,11 @@
<sha256 value="a8bdb8e14bb6813837e5db84b4d163cd5bc6761bb370d5e6ade28561522eb587" origin="Generated by Gradle"/> <sha256 value="a8bdb8e14bb6813837e5db84b4d163cd5bc6761bb370d5e6ade28561522eb587" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="org.apache.lucene" name="lucene-codecs" version="9.5.0-snapshot-d19c3e2e0ed">
<artifact name="lucene-codecs-9.5.0-snapshot-d19c3e2e0ed.jar">
<sha256 value="3f57ada190b4561df53d0521df67a64204b315720ccc4cc04a5f621cdac21a42" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.lucene" name="lucene-core" version="9.4.1"> <component group="org.apache.lucene" name="lucene-core" version="9.4.1">
<artifact name="lucene-core-9.4.1.jar"> <artifact name="lucene-core-9.4.1.jar">
<sha256 value="992f847526c953f734a18295901b6fbb8977a1d99275e01ed219e7e57cc0ae34" origin="Generated by Gradle"/> <sha256 value="992f847526c953f734a18295901b6fbb8977a1d99275e01ed219e7e57cc0ae34" origin="Generated by Gradle"/>
@ -2711,6 +2804,11 @@
<sha256 value="fd6db1bfe92c51439332230c1e95d2ac63633a9c3067d0355985594ff415431a" origin="Generated by Gradle"/> <sha256 value="fd6db1bfe92c51439332230c1e95d2ac63633a9c3067d0355985594ff415431a" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="org.apache.lucene" name="lucene-core" version="9.5.0-snapshot-d19c3e2e0ed">
<artifact name="lucene-core-9.5.0-snapshot-d19c3e2e0ed.jar">
<sha256 value="481c30915303e79477779b21fdf2769cd944dc5b5acef4ea2eac0bae5a5a59da" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.lucene" name="lucene-expressions" version="9.4.1"> <component group="org.apache.lucene" name="lucene-expressions" version="9.4.1">
<artifact name="lucene-expressions-9.4.1.jar"> <artifact name="lucene-expressions-9.4.1.jar">
<sha256 value="b037fbd8131443cf8a2f35f9c07eb68bf4d95cab01be67733a9225e7629a94e7" origin="Generated by Gradle"/> <sha256 value="b037fbd8131443cf8a2f35f9c07eb68bf4d95cab01be67733a9225e7629a94e7" origin="Generated by Gradle"/>
@ -2721,6 +2819,11 @@
<sha256 value="ed0366731de0a57c77e34113df8ea34c365f93d1e60556ec20dc253a10f516f5" origin="Generated by Gradle"/> <sha256 value="ed0366731de0a57c77e34113df8ea34c365f93d1e60556ec20dc253a10f516f5" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="org.apache.lucene" name="lucene-expressions" version="9.5.0-snapshot-d19c3e2e0ed">
<artifact name="lucene-expressions-9.5.0-snapshot-d19c3e2e0ed.jar">
<sha256 value="edc4e4d8398bf91bbda2717f835f0c94d816dcd26d7a7e2173a3563e8d25a719" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.lucene" name="lucene-grouping" version="9.4.1"> <component group="org.apache.lucene" name="lucene-grouping" version="9.4.1">
<artifact name="lucene-grouping-9.4.1.jar"> <artifact name="lucene-grouping-9.4.1.jar">
<sha256 value="dd88245285b240246280a4f922780a68831ed79df40a4884650d17902a33e361" origin="Generated by Gradle"/> <sha256 value="dd88245285b240246280a4f922780a68831ed79df40a4884650d17902a33e361" origin="Generated by Gradle"/>
@ -2731,6 +2834,11 @@
<sha256 value="0312ba56249fb252ae8842fd148bc231bf4f3c20569a66f92105f1739815381d" origin="Generated by Gradle"/> <sha256 value="0312ba56249fb252ae8842fd148bc231bf4f3c20569a66f92105f1739815381d" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="org.apache.lucene" name="lucene-grouping" version="9.5.0-snapshot-d19c3e2e0ed">
<artifact name="lucene-grouping-9.5.0-snapshot-d19c3e2e0ed.jar">
<sha256 value="91ac493aae11d211f2ffbe8457cf2f0c7aba68fcf2ddddb0d4da53b4d6b471cf" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.lucene" name="lucene-highlighter" version="9.4.1"> <component group="org.apache.lucene" name="lucene-highlighter" version="9.4.1">
<artifact name="lucene-highlighter-9.4.1.jar"> <artifact name="lucene-highlighter-9.4.1.jar">
<sha256 value="241af5dd27834d0a37e9ab2ef235aa125ca680181a78c51248511ee80c053240" origin="Generated by Gradle"/> <sha256 value="241af5dd27834d0a37e9ab2ef235aa125ca680181a78c51248511ee80c053240" origin="Generated by Gradle"/>
@ -2741,6 +2849,11 @@
<sha256 value="8512892073eb1c5f13a3fb1bf1b245cd66aeb1b45f7acfb47a83968a4141318d" origin="Generated by Gradle"/> <sha256 value="8512892073eb1c5f13a3fb1bf1b245cd66aeb1b45f7acfb47a83968a4141318d" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="org.apache.lucene" name="lucene-highlighter" version="9.5.0-snapshot-d19c3e2e0ed">
<artifact name="lucene-highlighter-9.5.0-snapshot-d19c3e2e0ed.jar">
<sha256 value="ff7eda5d69ef6aaad97fa36472252fc992d0151a6c8c5aad920ac05540be8a19" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.lucene" name="lucene-join" version="9.4.1"> <component group="org.apache.lucene" name="lucene-join" version="9.4.1">
<artifact name="lucene-join-9.4.1.jar"> <artifact name="lucene-join-9.4.1.jar">
<sha256 value="1dfd06b72ce8ac45e1747a1781bf7f75681de366e17e88756c171e506f0719bb" origin="Generated by Gradle"/> <sha256 value="1dfd06b72ce8ac45e1747a1781bf7f75681de366e17e88756c171e506f0719bb" origin="Generated by Gradle"/>
@ -2751,6 +2864,11 @@
<sha256 value="ae04eaa43bde57407a19aa9ab86038b8ee3b0d5c9d9333ecf63d283c306e6b0e" origin="Generated by Gradle"/> <sha256 value="ae04eaa43bde57407a19aa9ab86038b8ee3b0d5c9d9333ecf63d283c306e6b0e" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="org.apache.lucene" name="lucene-join" version="9.5.0-snapshot-d19c3e2e0ed">
<artifact name="lucene-join-9.5.0-snapshot-d19c3e2e0ed.jar">
<sha256 value="c29e7b0e2de53408c3d04b6562577679a3932a5f03c45b3d26ad22b1147f2132" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.lucene" name="lucene-memory" version="9.4.1"> <component group="org.apache.lucene" name="lucene-memory" version="9.4.1">
<artifact name="lucene-memory-9.4.1.jar"> <artifact name="lucene-memory-9.4.1.jar">
<sha256 value="2426d5a2475c9163dcc28b2e6f2624381abc2b83ede3f6140ab3833724ac60e6" origin="Generated by Gradle"/> <sha256 value="2426d5a2475c9163dcc28b2e6f2624381abc2b83ede3f6140ab3833724ac60e6" origin="Generated by Gradle"/>
@ -2761,6 +2879,11 @@
<sha256 value="a0c9dee125bed499005893dcd9737a02b3aebe3cfa01ce6eb8d28a4e3b5dc5d4" origin="Generated by Gradle"/> <sha256 value="a0c9dee125bed499005893dcd9737a02b3aebe3cfa01ce6eb8d28a4e3b5dc5d4" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="org.apache.lucene" name="lucene-memory" version="9.5.0-snapshot-d19c3e2e0ed">
<artifact name="lucene-memory-9.5.0-snapshot-d19c3e2e0ed.jar">
<sha256 value="f9ee01b34d8fa37e9b48426a00cf7e7fa947dd0356330ff9d14cefee345b2255" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.lucene" name="lucene-misc" version="9.4.1"> <component group="org.apache.lucene" name="lucene-misc" version="9.4.1">
<artifact name="lucene-misc-9.4.1.jar"> <artifact name="lucene-misc-9.4.1.jar">
<sha256 value="de8335139c1622234fc3c0d4973fcee9a7a7d53b26bc1b9ac72c3ba2c2f59b58" origin="Generated by Gradle"/> <sha256 value="de8335139c1622234fc3c0d4973fcee9a7a7d53b26bc1b9ac72c3ba2c2f59b58" origin="Generated by Gradle"/>
@ -2771,6 +2894,11 @@
<sha256 value="c3a3f2a487cf62bad685527f9ace8d4728aa173ab56054c328e6e397584e1992" origin="Generated by Gradle"/> <sha256 value="c3a3f2a487cf62bad685527f9ace8d4728aa173ab56054c328e6e397584e1992" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="org.apache.lucene" name="lucene-misc" version="9.5.0-snapshot-d19c3e2e0ed">
<artifact name="lucene-misc-9.5.0-snapshot-d19c3e2e0ed.jar">
<sha256 value="43c258c6016e776d70a248301f4586ab643491800ed1a887bacf1240aaad92a6" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.lucene" name="lucene-queries" version="9.4.1"> <component group="org.apache.lucene" name="lucene-queries" version="9.4.1">
<artifact name="lucene-queries-9.4.1.jar"> <artifact name="lucene-queries-9.4.1.jar">
<sha256 value="0fce03ae6070868fb7369763ea4a29aecdcc13c6342c7fc94c90d3ae29860a40" origin="Generated by Gradle"/> <sha256 value="0fce03ae6070868fb7369763ea4a29aecdcc13c6342c7fc94c90d3ae29860a40" origin="Generated by Gradle"/>
@ -2781,6 +2909,11 @@
<sha256 value="1924525c4c706706baecbac7f9c0e434630b9ce595e55ae6aa63ca6d465fb453" origin="Generated by Gradle"/> <sha256 value="1924525c4c706706baecbac7f9c0e434630b9ce595e55ae6aa63ca6d465fb453" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="org.apache.lucene" name="lucene-queries" version="9.5.0-snapshot-d19c3e2e0ed">
<artifact name="lucene-queries-9.5.0-snapshot-d19c3e2e0ed.jar">
<sha256 value="7b1534514f1766fc6b6851fcd18e24cbece06373a03410cf71e2b76f23c99bc1" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.lucene" name="lucene-queryparser" version="9.4.1"> <component group="org.apache.lucene" name="lucene-queryparser" version="9.4.1">
<artifact name="lucene-queryparser-9.4.1.jar"> <artifact name="lucene-queryparser-9.4.1.jar">
<sha256 value="c7bf66dea0ae9e7dc840347fd7eaefa9250a91f018bc2503888afed08010adea" origin="Generated by Gradle"/> <sha256 value="c7bf66dea0ae9e7dc840347fd7eaefa9250a91f018bc2503888afed08010adea" origin="Generated by Gradle"/>
@ -2791,6 +2924,11 @@
<sha256 value="dfc681a69bc60dd89e6bbf964a9b310b11e96de212da8597309b7caeb1cf591d" origin="Generated by Gradle"/> <sha256 value="dfc681a69bc60dd89e6bbf964a9b310b11e96de212da8597309b7caeb1cf591d" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="org.apache.lucene" name="lucene-queryparser" version="9.5.0-snapshot-d19c3e2e0ed">
<artifact name="lucene-queryparser-9.5.0-snapshot-d19c3e2e0ed.jar">
<sha256 value="b4542f0109a7a53c366ff0f4b2b22c573ab4a2400e928d9f0d065c1f731d6e8a" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.lucene" name="lucene-sandbox" version="9.4.1"> <component group="org.apache.lucene" name="lucene-sandbox" version="9.4.1">
<artifact name="lucene-sandbox-9.4.1.jar"> <artifact name="lucene-sandbox-9.4.1.jar">
<sha256 value="ddc756a446986101ab17ac15aedfeb14588832afff38b86c07a13cd93e6e4890" origin="Generated by Gradle"/> <sha256 value="ddc756a446986101ab17ac15aedfeb14588832afff38b86c07a13cd93e6e4890" origin="Generated by Gradle"/>
@ -2801,6 +2939,11 @@
<sha256 value="c381fe2797766d91b663a7cbee60e952a1c81dc37551445086f48f0dc5d47216" origin="Generated by Gradle"/> <sha256 value="c381fe2797766d91b663a7cbee60e952a1c81dc37551445086f48f0dc5d47216" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="org.apache.lucene" name="lucene-sandbox" version="9.5.0-snapshot-d19c3e2e0ed">
<artifact name="lucene-sandbox-9.5.0-snapshot-d19c3e2e0ed.jar">
<sha256 value="6c246106bd4ad6ac2a99ee8e87b76e25c7b17ffad333fbeed6206e3d23fba5ba" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.lucene" name="lucene-spatial-extras" version="9.4.1"> <component group="org.apache.lucene" name="lucene-spatial-extras" version="9.4.1">
<artifact name="lucene-spatial-extras-9.4.1.jar"> <artifact name="lucene-spatial-extras-9.4.1.jar">
<sha256 value="2fe68c8a9141af9f7a7862b576c88b74ad4509f5a2427cb423463d4233e76d4c" origin="Generated by Gradle"/> <sha256 value="2fe68c8a9141af9f7a7862b576c88b74ad4509f5a2427cb423463d4233e76d4c" origin="Generated by Gradle"/>
@ -2811,6 +2954,11 @@
<sha256 value="c13713f828a03d47d3634e59abc7a53df13c23531d1b6b70c72d190ff64c5cd4" origin="Generated by Gradle"/> <sha256 value="c13713f828a03d47d3634e59abc7a53df13c23531d1b6b70c72d190ff64c5cd4" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="org.apache.lucene" name="lucene-spatial-extras" version="9.5.0-snapshot-d19c3e2e0ed">
<artifact name="lucene-spatial-extras-9.5.0-snapshot-d19c3e2e0ed.jar">
<sha256 value="2ac4f5172e74a3772b68e86d5346f1edd88f4627d2fe3ce63e2b3d7717f36ee3" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.lucene" name="lucene-spatial3d" version="9.4.1"> <component group="org.apache.lucene" name="lucene-spatial3d" version="9.4.1">
<artifact name="lucene-spatial3d-9.4.1.jar"> <artifact name="lucene-spatial3d-9.4.1.jar">
<sha256 value="5911614baa3f6e75ee55d0ad63aa16286887766b2fda0654507ce6412d16353b" origin="Generated by Gradle"/> <sha256 value="5911614baa3f6e75ee55d0ad63aa16286887766b2fda0654507ce6412d16353b" origin="Generated by Gradle"/>
@ -2821,6 +2969,11 @@
<sha256 value="c9688a9ab51d5a827260892de6435595a0d524ff9426288af806eb595a000dbb" origin="Generated by Gradle"/> <sha256 value="c9688a9ab51d5a827260892de6435595a0d524ff9426288af806eb595a000dbb" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="org.apache.lucene" name="lucene-spatial3d" version="9.5.0-snapshot-d19c3e2e0ed">
<artifact name="lucene-spatial3d-9.5.0-snapshot-d19c3e2e0ed.jar">
<sha256 value="4f4d96e385ddb5187714f5ab274d0e8cb74cab56dedbc5fa1363389c98a617a1" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.lucene" name="lucene-suggest" version="9.4.1"> <component group="org.apache.lucene" name="lucene-suggest" version="9.4.1">
<artifact name="lucene-suggest-9.4.1.jar"> <artifact name="lucene-suggest-9.4.1.jar">
<sha256 value="0bd1662bfaa60d6cba12e69b74f90e162900ed077320fe37fbf9e8f5cd78e59f" origin="Generated by Gradle"/> <sha256 value="0bd1662bfaa60d6cba12e69b74f90e162900ed077320fe37fbf9e8f5cd78e59f" origin="Generated by Gradle"/>
@ -2831,6 +2984,11 @@
<sha256 value="0d56f92c5414149562ea50c6863ac50fcbbb51239d4a72c2bafbe852fb7e0a27" origin="Generated by Gradle"/> <sha256 value="0d56f92c5414149562ea50c6863ac50fcbbb51239d4a72c2bafbe852fb7e0a27" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="org.apache.lucene" name="lucene-suggest" version="9.5.0-snapshot-d19c3e2e0ed">
<artifact name="lucene-suggest-9.5.0-snapshot-d19c3e2e0ed.jar">
<sha256 value="94878bf9c520702c0d5293922dd06866e25bedbd6f9bb823e28eb34dac907197" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.lucene" name="lucene-test-framework" version="9.4.1"> <component group="org.apache.lucene" name="lucene-test-framework" version="9.4.1">
<artifact name="lucene-test-framework-9.4.1.jar"> <artifact name="lucene-test-framework-9.4.1.jar">
<sha256 value="63850af6b753e0802cba7697db7821727b9b2e23eef11177c1ddbfb37ef3eaf2" origin="Generated by Gradle"/> <sha256 value="63850af6b753e0802cba7697db7821727b9b2e23eef11177c1ddbfb37ef3eaf2" origin="Generated by Gradle"/>
@ -2841,6 +2999,11 @@
<sha256 value="be318e426e3ce93d704fff41abc8ccd09bb1def69a40615ecc549c21895dd79d" origin="Generated by Gradle"/> <sha256 value="be318e426e3ce93d704fff41abc8ccd09bb1def69a40615ecc549c21895dd79d" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="org.apache.lucene" name="lucene-test-framework" version="9.5.0-snapshot-d19c3e2e0ed">
<artifact name="lucene-test-framework-9.5.0-snapshot-d19c3e2e0ed.jar">
<sha256 value="561369612e4602cf99bcc53201b4bf9b95ed09096ba593e755416f1c96ff4bfb" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.apache.maven" name="maven-model" version="3.6.2"> <component group="org.apache.maven" name="maven-model" version="3.6.2">
<artifact name="maven-model-3.6.2.jar"> <artifact name="maven-model-3.6.2.jar">
<sha256 value="f4ada31d7217efc11d2264dec3716623cefa3440cfb2b6b1dcc640a825159a7d" origin="Generated by Gradle"/> <sha256 value="f4ada31d7217efc11d2264dec3716623cefa3440cfb2b6b1dcc640a825159a7d" origin="Generated by Gradle"/>
@ -3329,24 +3492,34 @@
<sha256 value="6cd91991323dd7b2fb28ca93d7ac12af5a86a2f53279e2b35827b30313fd0b9f" origin="Generated by Gradle"/> <sha256 value="6cd91991323dd7b2fb28ca93d7ac12af5a86a2f53279e2b35827b30313fd0b9f" origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="org.fusesource.leveldbjni" name="leveldbjni-all" version="1.8"> <component group="org.fusesource.leveldbjni" name="leveldbjni-all" version="1.8">
<artifact name="leveldbjni-all-1.8.jar"> <artifact name="leveldbjni-all-1.8.jar">
<sha256 value="c297213b0e6f9392305952753f3099a4c02e70b3656266fe01867e7b6c160ffe" origin="Generated by Gradle"/> <sha256 value="c297213b0e6f9392305952753f3099a4c02e70b3656266fe01867e7b6c160ffe"
</artifact> origin="Generated by Gradle"/>
</component> </artifact>
<component group="org.glassfish" name="javax.json" version="1.0.4"> </component>
<artifact name="javax.json-1.0.4.jar"> <component group="org.glassfish" name="javax.json" version="1.0.4">
<sha256 value="0e1dec40a1ede965941251eda968aeee052cc4f50378bc316cc48e8159bdbeb4" origin="Generated by Gradle"/> <artifact name="javax.json-1.0.4.jar">
</artifact> <sha256 value="0e1dec40a1ede965941251eda968aeee052cc4f50378bc316cc48e8159bdbeb4"
</component> origin="Generated by Gradle"/>
<component group="org.hamcrest" name="hamcrest" version="2.1"> </artifact>
<artifact name="hamcrest-2.1.jar"> </component>
<sha256 value="ba93b2e3a562322ba432f0a1b53addcc55cb188253319a020ed77f824e692050" origin="Generated by Gradle"/> <component group="org.glassfish" name="javax.json" version="1.1.4">
</artifact> <artifact name="javax.json-1.1.4.jar">
</component> <sha256 value="17fdeb7e22375a7fb40bb0551306f6dcf2b5743078668adcdf6c642c9a9ec955"
<component group="org.hamcrest" name="hamcrest" version="2.2"> origin="Generated by Gradle"/>
<artifact name="hamcrest-2.2.jar"> </artifact>
<sha256 value="5e62846a89f05cd78cd9c1a553f340d002458380c320455dd1f8fc5497a8a1c1" origin="Generated by Gradle"/> </component>
<component group="org.hamcrest" name="hamcrest" version="2.1">
<artifact name="hamcrest-2.1.jar">
<sha256 value="ba93b2e3a562322ba432f0a1b53addcc55cb188253319a020ed77f824e692050"
origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.hamcrest" name="hamcrest" version="2.2">
<artifact name="hamcrest-2.2.jar">
<sha256 value="5e62846a89f05cd78cd9c1a553f340d002458380c320455dd1f8fc5497a8a1c1"
origin="Generated by Gradle"/>
</artifact> </artifact>
</component> </component>
<component group="org.hamcrest" name="hamcrest-core" version="1.3"> <component group="org.hamcrest" name="hamcrest-core" version="1.3">

View file

@ -21,7 +21,6 @@ package org.elasticsearch.h3;
import com.carrotsearch.randomizedtesting.generators.RandomPicks; import com.carrotsearch.randomizedtesting.generators.RandomPicks;
import org.apache.lucene.geo.Point; import org.apache.lucene.geo.Point;
import org.apache.lucene.spatial3d.geom.GeoArea;
import org.apache.lucene.spatial3d.geom.GeoPoint; import org.apache.lucene.spatial3d.geom.GeoPoint;
import org.apache.lucene.spatial3d.geom.GeoPolygon; import org.apache.lucene.spatial3d.geom.GeoPolygon;
import org.apache.lucene.spatial3d.geom.GeoPolygonFactory; import org.apache.lucene.spatial3d.geom.GeoPolygonFactory;
@ -133,23 +132,13 @@ public class ParentChildNavigationTests extends ESTestCase {
public void testNoChildrenIntersecting() { public void testNoChildrenIntersecting() {
String[] h3Addresses = H3.getStringRes0Cells(); String[] h3Addresses = H3.getStringRes0Cells();
String h3Address = RandomPicks.randomFrom(random(), h3Addresses); String h3Address = RandomPicks.randomFrom(random(), h3Addresses);
// Once testIssue91915 is fixed, put upper limit of the loop to H3.MAX_H3_RES for (int i = 1; i <= H3.MAX_H3_RES; i++) {
for (int i = 1; i <= 10; i++) {
h3Addresses = H3.h3ToChildren(h3Address); h3Addresses = H3.h3ToChildren(h3Address);
assertIntersectingChildren(h3Address, h3Addresses); assertIntersectingChildren(h3Address, h3Addresses);
h3Address = RandomPicks.randomFrom(random(), h3Addresses); h3Address = RandomPicks.randomFrom(random(), h3Addresses);
} }
} }
public void testIssue91915() {
GeoPolygon polygon1 = getGeoPolygon("8ec82ea0650155f");
GeoPolygon polygon2 = getGeoPolygon("8ec82ea06501447");
// these polygons are disjoint but due to https://github.com/apache/lucene/issues/11883
// they are reported as intersects. Once this is fixed this test will fail, we should adjust
// testNoChildrenIntersecting
assertEquals("see https://github.com/elastic/elasticsearch/issues/91915", GeoArea.OVERLAPS, polygon1.getRelationship(polygon2));
}
private void assertIntersectingChildren(String h3Address, String[] children) { private void assertIntersectingChildren(String h3Address, String[] children) {
int size = H3.h3ToNotIntersectingChildrenSize(h3Address); int size = H3.h3ToNotIntersectingChildrenSize(h3Address);
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {

View file

@ -435,6 +435,22 @@ public final class XContentBuilder implements Closeable, Flushable {
return this; return this;
} }
public XContentBuilder array(String name, byte[] values) throws IOException {
return field(name).values(values);
}
private XContentBuilder values(byte[] values) throws IOException {
if (values == null) {
return nullValue();
}
startArray();
for (byte b : values) {
value(b);
}
endArray();
return this;
}
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Double // Double
////////////////////////////////// //////////////////////////////////

View file

@ -17,7 +17,7 @@ esplugin {
dependencies { dependencies {
api "org.apache.lucene:lucene-expressions:${versions.lucene}" api "org.apache.lucene:lucene-expressions:${versions.lucene}"
runtimeOnly "org.apache.lucene:lucene-codecs:${versions.lucene}" runtimeOnly "org.apache.lucene:lucene-codecs:${versions.lucene}"
runtimeOnly 'org.antlr:antlr4-runtime:4.5.1-1' runtimeOnly "org.antlr:antlr4-runtime:${versions.antlr4}"
runtimeOnly 'org.ow2.asm:asm:7.2' runtimeOnly 'org.ow2.asm:asm:7.2'
runtimeOnly 'org.ow2.asm:asm-commons:7.2' runtimeOnly 'org.ow2.asm:asm-commons:7.2'
runtimeOnly 'org.ow2.asm:asm-tree:7.2' runtimeOnly 'org.ow2.asm:asm-tree:7.2'

View file

@ -34,7 +34,7 @@ configurations {
} }
dependencies { dependencies {
api 'org.antlr:antlr4-runtime:4.5.3' api "org.antlr:antlr4-runtime:${versions.antlr4}"
api 'org.ow2.asm:asm-util:7.2' api 'org.ow2.asm:asm-util:7.2'
api 'org.ow2.asm:asm-tree:7.2' api 'org.ow2.asm:asm-tree:7.2'
api 'org.ow2.asm:asm-commons:7.2' api 'org.ow2.asm:asm-commons:7.2'
@ -174,7 +174,7 @@ configurations {
} }
dependencies { dependencies {
regenerate 'org.antlr:antlr4:4.5.3' regenerate "org.antlr:antlr4:${versions.antlr4}"
} }
String grammarPath = 'src/main/antlr' String grammarPath = 'src/main/antlr'
@ -274,7 +274,7 @@ configurations {
} }
dependencies { dependencies {
regenerate 'org.antlr:antlr4:4.5.3' regenerate "org.antlr:antlr4:${versions.antlr4}"
} }
String suggestGrammarPath = 'src/main/antlr' String suggestGrammarPath = 'src/main/antlr'

View file

@ -13,7 +13,7 @@ module org.elasticsearch.painless {
requires org.elasticsearch.server; requires org.elasticsearch.server;
requires org.elasticsearch.xcontent; requires org.elasticsearch.xcontent;
requires antlr4.runtime; requires org.antlr.antlr4.runtime;
requires org.apache.lucene.core; requires org.apache.lucene.core;
requires org.objectweb.asm; requires org.objectweb.asm;
requires org.objectweb.asm.commons; requires org.objectweb.asm.commons;

View file

@ -11,6 +11,7 @@ import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor;
* @param <T> The return type of the visit operation. Use {@link Void} for * @param <T> The return type of the visit operation. Use {@link Void} for
* operations with no return type. * operations with no return type.
*/ */
@SuppressWarnings("CheckReturnValue")
class PainlessParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> implements PainlessParserVisitor<T> { class PainlessParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> implements PainlessParserVisitor<T> {
/** /**
* {@inheritDoc} * {@inheritDoc}

View file

@ -131,7 +131,8 @@ public class Version implements Comparable<Version>, ToXContentFragment {
public static final Version V_8_5_4 = new Version(8_05_04_99, TransportVersion.V_8_5_4, org.apache.lucene.util.Version.LUCENE_9_4_2); public static final Version V_8_5_4 = new Version(8_05_04_99, TransportVersion.V_8_5_4, org.apache.lucene.util.Version.LUCENE_9_4_2);
public static final Version V_8_6_0 = new Version(8_06_00_99, TransportVersion.V_8_6_0, org.apache.lucene.util.Version.LUCENE_9_4_2); public static final Version V_8_6_0 = new Version(8_06_00_99, TransportVersion.V_8_6_0, org.apache.lucene.util.Version.LUCENE_9_4_2);
public static final Version V_8_6_1 = new Version(8_06_01_99, TransportVersion.V_8_6_1, org.apache.lucene.util.Version.LUCENE_9_4_2); public static final Version V_8_6_1 = new Version(8_06_01_99, TransportVersion.V_8_6_1, org.apache.lucene.util.Version.LUCENE_9_4_2);
public static final Version V_8_7_0 = new Version(8_07_00_99, TransportVersion.V_8_7_0, org.apache.lucene.util.Version.LUCENE_9_4_2); public static final Version V_8_7_0 = new Version(8_07_00_99, TransportVersion.V_8_7_0, org.apache.lucene.util.Version.LUCENE_9_5_0);
public static final Version CURRENT = V_8_7_0; public static final Version CURRENT = V_8_7_0;
private static final Map<Integer, Version> VERSION_IDS; private static final Map<Integer, Version> VERSION_IDS;

View file

@ -20,6 +20,7 @@ import org.apache.lucene.codecs.StoredFieldsReader;
import org.apache.lucene.codecs.TermVectorsReader; import org.apache.lucene.codecs.TermVectorsReader;
import org.apache.lucene.codecs.lucene90.Lucene90PostingsFormat; import org.apache.lucene.codecs.lucene90.Lucene90PostingsFormat;
import org.apache.lucene.index.BinaryDocValues; import org.apache.lucene.index.BinaryDocValues;
import org.apache.lucene.index.ByteVectorValues;
import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.DocValuesType; import org.apache.lucene.index.DocValuesType;
import org.apache.lucene.index.FieldInfo; import org.apache.lucene.index.FieldInfo;
@ -137,7 +138,7 @@ final class IndexDiskUsageAnalyzer {
final int skipMask = 0x1FF; // 511 final int skipMask = 0x1FF; // 511
while (docID < reader.maxDoc()) { while (docID < reader.maxDoc()) {
cancellationChecker.logEvent(); cancellationChecker.logEvent();
storedFieldsReader.visitDocument(docID, visitor); storedFieldsReader.document(docID, visitor);
// As we already estimate the size of stored fields, we can trade off the accuracy for the speed of the estimate. // As we already estimate the size of stored fields, we can trade off the accuracy for the speed of the estimate.
// Here we only visit 1/11 documents instead of all documents. Ideally, we should visit 1 doc then skip 10 docs // Here we only visit 1/11 documents instead of all documents. Ideally, we should visit 1 doc then skip 10 docs
// to avoid missing many skew documents. But, documents are stored in chunks in compressed format and a chunk can // to avoid missing many skew documents. But, documents are stored in chunks in compressed format and a chunk can
@ -525,23 +526,47 @@ final class IndexDiskUsageAnalyzer {
cancellationChecker.checkForCancellation(); cancellationChecker.checkForCancellation();
directory.resetBytesRead(); directory.resetBytesRead();
if (field.getVectorDimension() > 0) { if (field.getVectorDimension() > 0) {
iterateDocValues(reader.maxDoc(), () -> vectorReader.getVectorValues(field.name), vectors -> { switch (field.getVectorEncoding()) {
cancellationChecker.logEvent(); case BYTE -> {
vectors.vectorValue(); iterateDocValues(reader.maxDoc(), () -> vectorReader.getByteVectorValues(field.name), vectors -> {
}); cancellationChecker.logEvent();
vectors.vectorValue();
});
// do a couple of randomized searches to figure out min and max offsets of index file // do a couple of randomized searches to figure out min and max offsets of index file
VectorValues vectorValues = vectorReader.getVectorValues(field.name); ByteVectorValues vectorValues = vectorReader.getByteVectorValues(field.name);
int numDocsToVisit = reader.maxDoc() < 10 ? reader.maxDoc() : 10 * (int) Math.log10(reader.maxDoc()); int numDocsToVisit = reader.maxDoc() < 10 ? reader.maxDoc() : 10 * (int) Math.log10(reader.maxDoc());
int skipFactor = Math.max(reader.maxDoc() / numDocsToVisit, 1); int skipFactor = Math.max(reader.maxDoc() / numDocsToVisit, 1);
for (int i = 0; i < reader.maxDoc(); i += skipFactor) { for (int i = 0; i < reader.maxDoc(); i += skipFactor) {
if ((i = vectorValues.advance(i)) == DocIdSetIterator.NO_MORE_DOCS) { if ((i = vectorValues.advance(i)) == DocIdSetIterator.NO_MORE_DOCS) {
break; break;
}
cancellationChecker.checkForCancellation();
vectorReader.search(field.name, vectorValues.vectorValue(), 100, null, Integer.MAX_VALUE);
}
stats.addKnnVectors(field.name, directory.getBytesRead());
}
case FLOAT32 -> {
iterateDocValues(reader.maxDoc(), () -> vectorReader.getVectorValues(field.name), vectors -> {
cancellationChecker.logEvent();
vectors.vectorValue();
});
// do a couple of randomized searches to figure out min and max offsets of index file
VectorValues vectorValues = vectorReader.getVectorValues(field.name);
int numDocsToVisit = reader.maxDoc() < 10 ? reader.maxDoc() : 10 * (int) Math.log10(reader.maxDoc());
int skipFactor = Math.max(reader.maxDoc() / numDocsToVisit, 1);
for (int i = 0; i < reader.maxDoc(); i += skipFactor) {
if ((i = vectorValues.advance(i)) == DocIdSetIterator.NO_MORE_DOCS) {
break;
}
cancellationChecker.checkForCancellation();
vectorReader.search(field.name, vectorValues.vectorValue(), 100, null, Integer.MAX_VALUE);
}
stats.addKnnVectors(field.name, directory.getBytesRead());
} }
cancellationChecker.checkForCancellation();
vectorReader.search(field.name, vectorValues.vectorValue(), 100, null, Integer.MAX_VALUE);
} }
stats.addKnnVectors(field.name, directory.getBytesRead());
} }
} }
} }

View file

@ -86,7 +86,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
public class Lucene { public class Lucene {
public static final String LATEST_CODEC = "Lucene94"; public static final String LATEST_CODEC = "Lucene95";
public static final String SOFT_DELETES_FIELD = "__soft_deletes"; public static final String SOFT_DELETES_FIELD = "__soft_deletes";

View file

@ -299,7 +299,29 @@ public class MultiPhrasePrefixQuery extends Query {
@Override @Override
public void visit(QueryVisitor visitor) { public void visit(QueryVisitor visitor) {
if (visitor.acceptField(field)) { if (visitor.acceptField(field)) {
visitor.visitLeaf(this); // TODO implement term visiting visitor = visitor.getSubVisitor(BooleanClause.Occur.MUST, this);
for (int i = 0; i < termArrays.size() - 1; i++) {
if (termArrays.get(i).length == 1) {
visitor.consumeTerms(this, termArrays.get(i)[0]);
} else {
QueryVisitor shouldVisitor = visitor.getSubVisitor(BooleanClause.Occur.SHOULD, this);
shouldVisitor.consumeTerms(this, termArrays.get(i));
}
}
/* We don't report automata here because this breaks the unified highlighter,
which extracts automata separately from phrases. MPPQ gets rewritten to a
SpanMTQQuery by the PhraseHelper in any case, so highlighting is taken
care of there instead. If we extract automata here then the trailing prefix
word will be highlighted wherever it appears in the document, instead of only
as part of a phrase. This can be re-instated once we switch to using Matches
to highlight.
for (Term prefixTerm : termArrays.get(termArrays.size() - 1)) {
visitor.consumeTermsMatching(this, field, () -> {
CompiledAutomaton ca = new CompiledAutomaton(PrefixQuery.toAutomaton(prefixTerm.bytes()));
return ca.runAutomaton;
});
}
*/
} }
} }
} }

View file

@ -9,7 +9,7 @@
package org.elasticsearch.index.codec; package org.elasticsearch.index.codec;
import org.apache.lucene.codecs.Codec; import org.apache.lucene.codecs.Codec;
import org.apache.lucene.codecs.lucene94.Lucene94Codec; import org.apache.lucene.codecs.lucene95.Lucene95Codec;
import org.elasticsearch.common.util.BigArrays; import org.elasticsearch.common.util.BigArrays;
import org.elasticsearch.core.Nullable; import org.elasticsearch.core.Nullable;
import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.mapper.MapperService;
@ -35,11 +35,11 @@ public class CodecService {
public CodecService(@Nullable MapperService mapperService, BigArrays bigArrays) { public CodecService(@Nullable MapperService mapperService, BigArrays bigArrays) {
final var codecs = new HashMap<String, Codec>(); final var codecs = new HashMap<String, Codec>();
if (mapperService == null) { if (mapperService == null) {
codecs.put(DEFAULT_CODEC, new Lucene94Codec()); codecs.put(DEFAULT_CODEC, new Lucene95Codec());
codecs.put(BEST_COMPRESSION_CODEC, new Lucene94Codec(Lucene94Codec.Mode.BEST_COMPRESSION)); codecs.put(BEST_COMPRESSION_CODEC, new Lucene95Codec(Lucene95Codec.Mode.BEST_COMPRESSION));
} else { } else {
codecs.put(DEFAULT_CODEC, new PerFieldMapperCodec(Lucene94Codec.Mode.BEST_SPEED, mapperService, bigArrays)); codecs.put(DEFAULT_CODEC, new PerFieldMapperCodec(Lucene95Codec.Mode.BEST_SPEED, mapperService, bigArrays));
codecs.put(BEST_COMPRESSION_CODEC, new PerFieldMapperCodec(Lucene94Codec.Mode.BEST_COMPRESSION, mapperService, bigArrays)); codecs.put(BEST_COMPRESSION_CODEC, new PerFieldMapperCodec(Lucene95Codec.Mode.BEST_COMPRESSION, mapperService, bigArrays));
} }
codecs.put(LUCENE_DEFAULT_CODEC, Codec.getDefault()); codecs.put(LUCENE_DEFAULT_CODEC, Codec.getDefault());
for (String codec : Codec.availableCodecs()) { for (String codec : Codec.availableCodecs()) {

View file

@ -13,7 +13,7 @@ import org.apache.lucene.codecs.DocValuesFormat;
import org.apache.lucene.codecs.KnnVectorsFormat; import org.apache.lucene.codecs.KnnVectorsFormat;
import org.apache.lucene.codecs.PostingsFormat; import org.apache.lucene.codecs.PostingsFormat;
import org.apache.lucene.codecs.lucene90.Lucene90DocValuesFormat; import org.apache.lucene.codecs.lucene90.Lucene90DocValuesFormat;
import org.apache.lucene.codecs.lucene94.Lucene94Codec; import org.apache.lucene.codecs.lucene95.Lucene95Codec;
import org.elasticsearch.common.lucene.Lucene; import org.elasticsearch.common.lucene.Lucene;
import org.elasticsearch.common.util.BigArrays; import org.elasticsearch.common.util.BigArrays;
import org.elasticsearch.index.IndexMode; import org.elasticsearch.index.IndexMode;
@ -37,7 +37,7 @@ import org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper;
* per index in real time via the mapping API. If no specific postings format or vector format is * per index in real time via the mapping API. If no specific postings format or vector format is
* configured for a specific field the default postings or vector format is used. * configured for a specific field the default postings or vector format is used.
*/ */
public class PerFieldMapperCodec extends Lucene94Codec { public class PerFieldMapperCodec extends Lucene95Codec {
private final MapperService mapperService; private final MapperService mapperService;
private final DocValuesFormat docValuesFormat = new Lucene90DocValuesFormat(); private final DocValuesFormat docValuesFormat = new Lucene90DocValuesFormat();

View file

@ -35,7 +35,7 @@ final class IdStoredFieldLoader {
private static CheckedBiConsumer<Integer, StoredFieldVisitor, IOException> getStoredFieldsReader(LeafReader in) { private static CheckedBiConsumer<Integer, StoredFieldVisitor, IOException> getStoredFieldsReader(LeafReader in) {
if (in instanceof SequentialStoredFieldsLeafReader) { if (in instanceof SequentialStoredFieldsLeafReader) {
return (((SequentialStoredFieldsLeafReader) in).getSequentialStoredFieldsReader())::visitDocument; return (((SequentialStoredFieldsLeafReader) in).getSequentialStoredFieldsReader())::document;
} }
throw new IllegalArgumentException("Requires a SequentialStoredFieldsReader, got " + in.getClass()); throw new IllegalArgumentException("Requires a SequentialStoredFieldsReader, got " + in.getClass());
} }

View file

@ -338,7 +338,7 @@ final class LuceneChangesSnapshot implements Translog.Snapshot {
assert singleConsumer : "Sequential access optimization must not be enabled for multiple consumers"; assert singleConsumer : "Sequential access optimization must not be enabled for multiple consumers";
assert parallelArray.useSequentialStoredFieldsReader; assert parallelArray.useSequentialStoredFieldsReader;
assert storedFieldsReaderOrd == leaf.ord : storedFieldsReaderOrd + " != " + leaf.ord; assert storedFieldsReaderOrd == leaf.ord : storedFieldsReaderOrd + " != " + leaf.ord;
storedFieldsReader.visitDocument(segmentDocID, fields); storedFieldsReader.document(segmentDocID, fields);
} else { } else {
leaf.reader().document(segmentDocID, fields); leaf.reader().document(segmentDocID, fields);
} }

View file

@ -195,8 +195,8 @@ final class RecoverySourcePruneMergePolicy extends OneMergeWrappingMergePolicy {
} }
@Override @Override
public void visitDocument(int docID, StoredFieldVisitor visitor) throws IOException { public void document(int docID, StoredFieldVisitor visitor) throws IOException {
in.visitDocument(docID, visitor); in.document(docID, visitor);
} }
@Override @Override
@ -220,11 +220,11 @@ final class RecoverySourcePruneMergePolicy extends OneMergeWrappingMergePolicy {
} }
@Override @Override
public void visitDocument(int docID, StoredFieldVisitor visitor) throws IOException { public void document(int docID, StoredFieldVisitor visitor) throws IOException {
if (recoverySourceToKeep != null && recoverySourceToKeep.get(docID)) { if (recoverySourceToKeep != null && recoverySourceToKeep.get(docID)) {
super.visitDocument(docID, visitor); super.document(docID, visitor);
} else { } else {
super.visitDocument(docID, new FilterStoredFieldVisitor(visitor) { super.document(docID, new FilterStoredFieldVisitor(visitor) {
@Override @Override
public Status needsField(FieldInfo fieldInfo) throws IOException { public Status needsField(FieldInfo fieldInfo) throws IOException {
if (recoverySourceField.equals(fieldInfo.name)) { if (recoverySourceField.equals(fieldInfo.name)) {

View file

@ -11,6 +11,7 @@ package org.elasticsearch.index.engine;
import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.index.BaseTermsEnum; import org.apache.lucene.index.BaseTermsEnum;
import org.apache.lucene.index.BinaryDocValues; import org.apache.lucene.index.BinaryDocValues;
import org.apache.lucene.index.ByteVectorValues;
import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.DocValuesType; import org.apache.lucene.index.DocValuesType;
import org.apache.lucene.index.FieldInfo; import org.apache.lucene.index.FieldInfo;
@ -30,6 +31,8 @@ import org.apache.lucene.index.SortedDocValues;
import org.apache.lucene.index.SortedNumericDocValues; import org.apache.lucene.index.SortedNumericDocValues;
import org.apache.lucene.index.SortedSetDocValues; import org.apache.lucene.index.SortedSetDocValues;
import org.apache.lucene.index.StoredFieldVisitor; import org.apache.lucene.index.StoredFieldVisitor;
import org.apache.lucene.index.StoredFields;
import org.apache.lucene.index.TermVectors;
import org.apache.lucene.index.Terms; import org.apache.lucene.index.Terms;
import org.apache.lucene.index.TermsEnum; import org.apache.lucene.index.TermsEnum;
import org.apache.lucene.index.VectorEncoding; import org.apache.lucene.index.VectorEncoding;
@ -349,11 +352,21 @@ final class TranslogDirectoryReader extends DirectoryReader {
return getDelegate().getVectorValues(field); return getDelegate().getVectorValues(field);
} }
@Override
public ByteVectorValues getByteVectorValues(String field) throws IOException {
return getDelegate().getByteVectorValues(field);
}
@Override @Override
public TopDocs searchNearestVectors(String field, float[] target, int k, Bits acceptDocs, int visitedLimit) throws IOException { public TopDocs searchNearestVectors(String field, float[] target, int k, Bits acceptDocs, int visitedLimit) throws IOException {
return getDelegate().searchNearestVectors(field, target, k, acceptDocs, visitedLimit); return getDelegate().searchNearestVectors(field, target, k, acceptDocs, visitedLimit);
} }
@Override
public TopDocs searchNearestVectors(String field, BytesRef target, int k, Bits acceptDocs, int visitedLimit) throws IOException {
return getDelegate().searchNearestVectors(field, target, k, acceptDocs, visitedLimit);
}
@Override @Override
public FieldInfos getFieldInfos() { public FieldInfos getFieldInfos() {
return getDelegate().getFieldInfos(); return getDelegate().getFieldInfos();
@ -382,6 +395,16 @@ final class TranslogDirectoryReader extends DirectoryReader {
return getDelegate().getTermVectors(docID); return getDelegate().getTermVectors(docID);
} }
@Override
public TermVectors termVectors() throws IOException {
return getDelegate().termVectors();
}
@Override
public StoredFields storedFields() throws IOException {
return getDelegate().storedFields();
}
@Override @Override
public int numDocs() { public int numDocs() {
return 1; return 1;

View file

@ -108,7 +108,7 @@ public abstract class StoredFieldLoader {
private static CheckedBiConsumer<Integer, FieldsVisitor, IOException> sequentialReader(LeafReaderContext ctx) { private static CheckedBiConsumer<Integer, FieldsVisitor, IOException> sequentialReader(LeafReaderContext ctx) {
LeafReader leafReader = ctx.reader(); LeafReader leafReader = ctx.reader();
if (leafReader instanceof SequentialStoredFieldsLeafReader lf) { if (leafReader instanceof SequentialStoredFieldsLeafReader lf) {
return lf.getSequentialStoredFieldsReader()::visitDocument; return lf.getSequentialStoredFieldsReader()::document;
} }
return leafReader::document; return leafReader::document;
} }

View file

@ -17,8 +17,8 @@ import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.PointValues; import org.apache.lucene.index.PointValues;
import org.apache.lucene.index.SortedNumericDocValues; import org.apache.lucene.index.SortedNumericDocValues;
import org.apache.lucene.sandbox.search.IndexSortSortedNumericDocValuesRangeQuery;
import org.apache.lucene.search.IndexOrDocValuesQuery; import org.apache.lucene.search.IndexOrDocValuesQuery;
import org.apache.lucene.search.IndexSortSortedNumericDocValuesRangeQuery;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.Version; import org.elasticsearch.Version;

View file

@ -9,6 +9,7 @@
package org.elasticsearch.index.mapper; package org.elasticsearch.index.mapper;
import org.apache.lucene.index.BinaryDocValues; import org.apache.lucene.index.BinaryDocValues;
import org.apache.lucene.index.ByteVectorValues;
import org.apache.lucene.index.DocValuesType; import org.apache.lucene.index.DocValuesType;
import org.apache.lucene.index.FieldInfo; import org.apache.lucene.index.FieldInfo;
import org.apache.lucene.index.FieldInfos; import org.apache.lucene.index.FieldInfos;
@ -24,6 +25,8 @@ import org.apache.lucene.index.SortedDocValues;
import org.apache.lucene.index.SortedNumericDocValues; import org.apache.lucene.index.SortedNumericDocValues;
import org.apache.lucene.index.SortedSetDocValues; import org.apache.lucene.index.SortedSetDocValues;
import org.apache.lucene.index.StoredFieldVisitor; import org.apache.lucene.index.StoredFieldVisitor;
import org.apache.lucene.index.StoredFields;
import org.apache.lucene.index.TermVectors;
import org.apache.lucene.index.Terms; import org.apache.lucene.index.Terms;
import org.apache.lucene.index.VectorEncoding; import org.apache.lucene.index.VectorEncoding;
import org.apache.lucene.index.VectorSimilarityFunction; import org.apache.lucene.index.VectorSimilarityFunction;
@ -46,10 +49,9 @@ import java.util.function.Consumer;
/** /**
* A {@link LeafReader} over a lucene document that exposes doc values and stored fields. * A {@link LeafReader} over a lucene document that exposes doc values and stored fields.
* Note that unlike lucene's {@link MemoryIndex} implementation, this holds no state and * Note that unlike lucene's {@link MemoryIndex} implementation, this holds no state and
* does not attempt to do any analysis on text fields. It also supports stored * does not attempt to do any analysis on text fields. It is used to back index-time
* fields where MemoryIndex does not. It is used to back index-time scripts that * scripts that reference field data and stored fields from a document that has not yet
* reference field data and stored fields from a document that has not yet been * been indexed.
* indexed.
*/ */
class DocumentLeafReader extends LeafReader { class DocumentLeafReader extends LeafReader {
@ -175,6 +177,11 @@ class DocumentLeafReader extends LeafReader {
} }
} }
@Override
public StoredFields storedFields() throws IOException {
throw new UnsupportedOperationException();
}
@Override @Override
public CacheHelper getCoreCacheHelper() { public CacheHelper getCoreCacheHelper() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
@ -240,6 +247,21 @@ class DocumentLeafReader extends LeafReader {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public ByteVectorValues getByteVectorValues(String field) {
throw new UnsupportedOperationException();
}
@Override
public TopDocs searchNearestVectors(String field, BytesRef target, int k, Bits acceptDocs, int visitedLimit) {
throw new UnsupportedOperationException();
}
@Override
public TermVectors termVectors() throws IOException {
throw new UnsupportedOperationException();
}
@Override @Override
public CacheHelper getReaderCacheHelper() { public CacheHelper getReaderCacheHelper() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();

View file

@ -17,8 +17,8 @@ import org.apache.lucene.document.StoredField;
import org.apache.lucene.index.IndexableField; import org.apache.lucene.index.IndexableField;
import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.sandbox.document.HalfFloatPoint; import org.apache.lucene.sandbox.document.HalfFloatPoint;
import org.apache.lucene.sandbox.search.IndexSortSortedNumericDocValuesRangeQuery;
import org.apache.lucene.search.IndexOrDocValuesQuery; import org.apache.lucene.search.IndexOrDocValuesQuery;
import org.apache.lucene.search.IndexSortSortedNumericDocValuesRangeQuery;
import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRef;

View file

@ -9,19 +9,21 @@
package org.elasticsearch.index.mapper.vectors; package org.elasticsearch.index.mapper.vectors;
import org.apache.lucene.codecs.KnnVectorsFormat; import org.apache.lucene.codecs.KnnVectorsFormat;
import org.apache.lucene.codecs.lucene94.Lucene94HnswVectorsFormat; import org.apache.lucene.codecs.lucene95.Lucene95HnswVectorsFormat;
import org.apache.lucene.document.BinaryDocValuesField; import org.apache.lucene.document.BinaryDocValuesField;
import org.apache.lucene.document.Field; import org.apache.lucene.document.Field;
import org.apache.lucene.document.KnnByteVectorField;
import org.apache.lucene.document.KnnVectorField; import org.apache.lucene.document.KnnVectorField;
import org.apache.lucene.index.BinaryDocValues; import org.apache.lucene.index.BinaryDocValues;
import org.apache.lucene.index.ByteVectorValues;
import org.apache.lucene.index.LeafReader; import org.apache.lucene.index.LeafReader;
import org.apache.lucene.index.VectorSimilarityFunction; import org.apache.lucene.index.VectorSimilarityFunction;
import org.apache.lucene.index.VectorValues; import org.apache.lucene.index.VectorValues;
import org.apache.lucene.search.FieldExistsQuery; import org.apache.lucene.search.FieldExistsQuery;
import org.apache.lucene.search.KnnByteVectorQuery;
import org.apache.lucene.search.KnnVectorQuery; import org.apache.lucene.search.KnnVectorQuery;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.VectorUtil;
import org.elasticsearch.Version; import org.elasticsearch.Version;
import org.elasticsearch.common.xcontent.support.XContentMapValues; import org.elasticsearch.common.xcontent.support.XContentMapValues;
import org.elasticsearch.index.fielddata.FieldDataContext; import org.elasticsearch.index.fielddata.FieldDataContext;
@ -43,6 +45,7 @@ import org.elasticsearch.search.DocValueFormat;
import org.elasticsearch.search.aggregations.support.CoreValuesSourceType; import org.elasticsearch.search.aggregations.support.CoreValuesSourceType;
import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xcontent.ToXContent;
import org.elasticsearch.xcontent.XContentBuilder; import org.elasticsearch.xcontent.XContentBuilder;
import org.elasticsearch.xcontent.XContentParser;
import org.elasticsearch.xcontent.XContentParser.Token; import org.elasticsearch.xcontent.XContentParser.Token;
import java.io.IOException; import java.io.IOException;
@ -51,6 +54,7 @@ import java.time.ZoneId;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Stream; import java.util.stream.Stream;
import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken; import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
@ -178,13 +182,18 @@ public class DenseVectorFieldMapper extends FieldMapper {
} }
@Override @Override
public float readValue(ByteBuffer byteBuffer) { public void readAndWriteValue(ByteBuffer byteBuffer, XContentBuilder b) throws IOException {
return byteBuffer.get(); b.value(byteBuffer.get());
}
@Override
KnnByteVectorField createKnnVectorField(String name, BytesRef vector, VectorSimilarityFunction function) {
return new KnnByteVectorField(name, vector, function);
} }
@Override @Override
KnnVectorField createKnnVectorField(String name, float[] vector, VectorSimilarityFunction function) { KnnVectorField createKnnVectorField(String name, float[] vector, VectorSimilarityFunction function) {
return new KnnVectorField(name, VectorUtil.toBytesRef(vector), function); throw new IllegalArgumentException("cannot create a float vector field from byte");
} }
@Override @Override
@ -245,7 +254,11 @@ public class DenseVectorFieldMapper extends FieldMapper {
} }
@Override @Override
void checkVectorMagnitude(VectorSimilarity similarity, float[] vector, float squaredMagnitude) { void checkVectorMagnitude(
VectorSimilarity similarity,
Function<StringBuilder, StringBuilder> appender,
float squaredMagnitude
) {
StringBuilder errorBuilder = null; StringBuilder errorBuilder = null;
if (similarity == VectorSimilarity.COSINE && Math.sqrt(squaredMagnitude) == 0.0f) { if (similarity == VectorSimilarity.COSINE && Math.sqrt(squaredMagnitude) == 0.0f) {
@ -255,9 +268,91 @@ public class DenseVectorFieldMapper extends FieldMapper {
} }
if (errorBuilder != null) { if (errorBuilder != null) {
throw new IllegalArgumentException(appendErrorElements(errorBuilder, vector).toString()); throw new IllegalArgumentException(appender.apply(errorBuilder).toString());
} }
} }
@Override
public Field parseKnnVector(DocumentParserContext context, DenseVectorFieldMapper fieldMapper) throws IOException {
int index = 0;
byte[] vector = new byte[fieldMapper.dims];
float squaredMagnitude = 0;
for (Token token = context.parser().nextToken(); token != Token.END_ARRAY; token = context.parser().nextToken()) {
fieldMapper.checkDimensionExceeded(index, context);
ensureExpectedToken(Token.VALUE_NUMBER, token, context.parser());
final int value;
if (context.parser().numberType() != XContentParser.NumberType.INT) {
float floatValue = context.parser().floatValue(true);
if (floatValue % 1.0f != 0.0f) {
throw new IllegalArgumentException(
"element_type ["
+ this
+ "] vectors only support non-decimal values but found decimal value ["
+ floatValue
+ "] at dim ["
+ index
+ "];"
);
}
value = (int) floatValue;
} else {
value = context.parser().intValue(true);
}
if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) {
throw new IllegalArgumentException(
"element_type ["
+ this
+ "] vectors only support integers between ["
+ Byte.MIN_VALUE
+ ", "
+ Byte.MAX_VALUE
+ "] but found ["
+ value
+ "] at dim ["
+ index
+ "];"
);
}
vector[index++] = (byte) value;
squaredMagnitude += value * value;
}
fieldMapper.checkDimensionMatches(index, context);
BytesRef bytesVector = new BytesRef(vector);
checkVectorMagnitude(fieldMapper.similarity, errorByteElementsAppender(bytesVector), squaredMagnitude);
return createKnnVectorField(fieldMapper.fieldType().name(), bytesVector, fieldMapper.similarity.function);
}
@Override
double parseKnnVectorToByteBuffer(DocumentParserContext context, DenseVectorFieldMapper fieldMapper, ByteBuffer byteBuffer)
throws IOException {
double dotProduct = 0f;
int index = 0;
for (Token token = context.parser().nextToken(); token != Token.END_ARRAY; token = context.parser().nextToken()) {
fieldMapper.checkDimensionExceeded(index, context);
ensureExpectedToken(Token.VALUE_NUMBER, token, context.parser());
int value = context.parser().intValue(true);
if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) {
throw new IllegalArgumentException(
"element_type ["
+ this
+ "] vectors only support integers between ["
+ Byte.MIN_VALUE
+ ", "
+ Byte.MAX_VALUE
+ "] but found ["
+ value
+ "] at dim ["
+ index
+ "];"
);
}
byteBuffer.put((byte) value);
dotProduct += value * value;
index++;
}
fieldMapper.checkDimensionMatches(index, context);
return dotProduct;
}
}, },
FLOAT(4) { FLOAT(4) {
@ -273,8 +368,8 @@ public class DenseVectorFieldMapper extends FieldMapper {
} }
@Override @Override
public float readValue(ByteBuffer byteBuffer) { public void readAndWriteValue(ByteBuffer byteBuffer, XContentBuilder b) throws IOException {
return byteBuffer.getFloat(); b.value(byteBuffer.getFloat());
} }
@Override @Override
@ -282,6 +377,11 @@ public class DenseVectorFieldMapper extends FieldMapper {
return new KnnVectorField(name, vector, function); return new KnnVectorField(name, vector, function);
} }
@Override
KnnByteVectorField createKnnVectorField(String name, BytesRef vector, VectorSimilarityFunction function) {
throw new IllegalArgumentException("cannot create a byte vector field from float");
}
@Override @Override
IndexFieldData.Builder fielddataBuilder(DenseVectorFieldType denseVectorFieldType, FieldDataContext fieldDataContext) { IndexFieldData.Builder fielddataBuilder(DenseVectorFieldType denseVectorFieldType, FieldDataContext fieldDataContext) {
return new VectorIndexFieldData.Builder( return new VectorIndexFieldData.Builder(
@ -300,7 +400,11 @@ public class DenseVectorFieldMapper extends FieldMapper {
} }
@Override @Override
void checkVectorMagnitude(VectorSimilarity similarity, float[] vector, float squaredMagnitude) { void checkVectorMagnitude(
VectorSimilarity similarity,
Function<StringBuilder, StringBuilder> appender,
float squaredMagnitude
) {
StringBuilder errorBuilder = null; StringBuilder errorBuilder = null;
if (similarity == VectorSimilarity.DOT_PRODUCT && Math.abs(squaredMagnitude - 1.0f) > 1e-4f) { if (similarity == VectorSimilarity.DOT_PRODUCT && Math.abs(squaredMagnitude - 1.0f) > 1e-4f) {
@ -314,9 +418,48 @@ public class DenseVectorFieldMapper extends FieldMapper {
} }
if (errorBuilder != null) { if (errorBuilder != null) {
throw new IllegalArgumentException(appendErrorElements(errorBuilder, vector).toString()); throw new IllegalArgumentException(appender.apply(errorBuilder).toString());
} }
} }
@Override
public Field parseKnnVector(DocumentParserContext context, DenseVectorFieldMapper fieldMapper) throws IOException {
int index = 0;
float[] vector = new float[fieldMapper.dims];
float squaredMagnitude = 0;
for (Token token = context.parser().nextToken(); token != Token.END_ARRAY; token = context.parser().nextToken()) {
fieldMapper.checkDimensionExceeded(index, context);
ensureExpectedToken(Token.VALUE_NUMBER, token, context.parser());
float value = context.parser().floatValue(true);
vector[index++] = value;
squaredMagnitude += value * value;
}
fieldMapper.checkDimensionMatches(index, context);
checkVectorBounds(vector);
checkVectorMagnitude(fieldMapper.similarity, errorFloatElementsAppender(vector), squaredMagnitude);
return createKnnVectorField(fieldMapper.fieldType().name(), vector, fieldMapper.similarity.function);
}
@Override
double parseKnnVectorToByteBuffer(DocumentParserContext context, DenseVectorFieldMapper fieldMapper, ByteBuffer byteBuffer)
throws IOException {
double dotProduct = 0f;
int index = 0;
float[] vector = new float[fieldMapper.dims];
for (Token token = context.parser().nextToken(); token != Token.END_ARRAY; token = context.parser().nextToken()) {
fieldMapper.checkDimensionExceeded(index, context);
ensureExpectedToken(Token.VALUE_NUMBER, token, context.parser());
float value = context.parser().floatValue(true);
vector[index] = value;
byteBuffer.putFloat(value);
dotProduct += value * value;
index++;
}
fieldMapper.checkDimensionMatches(index, context);
checkVectorBounds(vector);
return dotProduct;
}
}; };
final int elementBytes; final int elementBytes;
@ -327,15 +470,26 @@ public class DenseVectorFieldMapper extends FieldMapper {
public abstract void writeValue(ByteBuffer byteBuffer, float value); public abstract void writeValue(ByteBuffer byteBuffer, float value);
public abstract float readValue(ByteBuffer byteBuffer); public abstract void readAndWriteValue(ByteBuffer byteBuffer, XContentBuilder b) throws IOException;
abstract KnnVectorField createKnnVectorField(String name, float[] vector, VectorSimilarityFunction function); abstract KnnVectorField createKnnVectorField(String name, float[] vector, VectorSimilarityFunction function);
abstract KnnByteVectorField createKnnVectorField(String name, BytesRef vector, VectorSimilarityFunction function);
abstract IndexFieldData.Builder fielddataBuilder(DenseVectorFieldType denseVectorFieldType, FieldDataContext fieldDataContext); abstract IndexFieldData.Builder fielddataBuilder(DenseVectorFieldType denseVectorFieldType, FieldDataContext fieldDataContext);
abstract Field parseKnnVector(DocumentParserContext context, DenseVectorFieldMapper fieldMapper) throws IOException;
abstract double parseKnnVectorToByteBuffer(DocumentParserContext context, DenseVectorFieldMapper fieldMapper, ByteBuffer byteBuffer)
throws IOException;
public abstract void checkVectorBounds(float[] vector); public abstract void checkVectorBounds(float[] vector);
abstract void checkVectorMagnitude(VectorSimilarity similarity, float[] vector, float squaredMagnitude); abstract void checkVectorMagnitude(
VectorSimilarity similarity,
Function<StringBuilder, StringBuilder> errorElementsAppender,
float squaredMagnitude
);
void checkNanAndInfinite(float[] vector) { void checkNanAndInfinite(float[] vector) {
StringBuilder errorBuilder = null; StringBuilder errorBuilder = null;
@ -384,6 +538,30 @@ public class DenseVectorFieldMapper extends FieldMapper {
errorBuilder.append("]"); errorBuilder.append("]");
return errorBuilder; return errorBuilder;
} }
StringBuilder appendErrorElements(StringBuilder errorBuilder, BytesRef vector) {
// Include the first five elements of the invalid vector in the error message
errorBuilder.append(" Preview of invalid vector: [");
for (int i = vector.offset; i < vector.offset + Math.min(5, vector.length); i++) {
if (i > vector.offset) {
errorBuilder.append(", ");
}
errorBuilder.append(vector.bytes[i]);
}
if (vector.length >= 5) {
errorBuilder.append(", ...");
}
errorBuilder.append("]");
return errorBuilder;
}
Function<StringBuilder, StringBuilder> errorFloatElementsAppender(float[] vector) {
return sb -> appendErrorElements(sb, vector);
}
Function<StringBuilder, StringBuilder> errorByteElementsAppender(BytesRef vector) {
return sb -> appendErrorElements(sb, vector);
}
} }
static final Map<String, ElementType> namesToElementType = Map.of( static final Map<String, ElementType> namesToElementType = Map.of(
@ -546,7 +724,7 @@ public class DenseVectorFieldMapper extends FieldMapper {
throw new IllegalArgumentException("Field [" + name() + "] of type [" + typeName() + "] doesn't support term queries"); throw new IllegalArgumentException("Field [" + name() + "] of type [" + typeName() + "] doesn't support term queries");
} }
public KnnVectorQuery createKnnQuery(float[] queryVector, int numCands, Query filter) { public Query createKnnQuery(BytesRef queryVector, int numCands, Query filter) {
if (isIndexed() == false) { if (isIndexed() == false) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"to perform knn search on field [" + name() + "], its mapping must have [index] set to [true]" "to perform knn search on field [" + name() + "], its mapping must have [index] set to [true]"
@ -559,6 +737,35 @@ public class DenseVectorFieldMapper extends FieldMapper {
); );
} }
if (elementType != ElementType.BYTE) {
throw new IllegalArgumentException(
"only [" + ElementType.BYTE + "] elements are supported when querying field [" + name() + "]"
);
}
if (similarity == VectorSimilarity.DOT_PRODUCT || similarity == VectorSimilarity.COSINE) {
float squaredMagnitude = 0.0f;
for (int i = queryVector.offset; i < queryVector.offset + queryVector.length; i++) {
squaredMagnitude += queryVector.bytes[i] * queryVector.bytes[i];
}
elementType.checkVectorMagnitude(similarity, elementType.errorByteElementsAppender(queryVector), squaredMagnitude);
}
return new KnnByteVectorQuery(name(), queryVector, numCands, filter);
}
public Query createKnnQuery(float[] queryVector, int numCands, Query filter) {
if (isIndexed() == false) {
throw new IllegalArgumentException(
"to perform knn search on field [" + name() + "], its mapping must have [index] set to [true]"
);
}
if (queryVector.length != dims) {
throw new IllegalArgumentException(
"the query vector has a different dimension [" + queryVector.length + "] than the index vectors [" + dims + "]"
);
}
elementType.checkVectorBounds(queryVector); elementType.checkVectorBounds(queryVector);
if (similarity == VectorSimilarity.DOT_PRODUCT || similarity == VectorSimilarity.COSINE) { if (similarity == VectorSimilarity.DOT_PRODUCT || similarity == VectorSimilarity.COSINE) {
@ -566,10 +773,18 @@ public class DenseVectorFieldMapper extends FieldMapper {
for (float e : queryVector) { for (float e : queryVector) {
squaredMagnitude += e * e; squaredMagnitude += e * e;
} }
elementType.checkVectorMagnitude(similarity, queryVector, squaredMagnitude); elementType.checkVectorMagnitude(similarity, elementType.errorFloatElementsAppender(queryVector), squaredMagnitude);
} }
return switch (elementType) {
return new KnnVectorQuery(name(), queryVector, numCands, filter); case BYTE -> {
byte[] bytes = new byte[queryVector.length];
for (int i = 0; i < queryVector.length; i++) {
bytes[i] = (byte) queryVector[i];
}
yield new KnnByteVectorQuery(name(), new BytesRef(bytes), numCands, filter);
}
case FLOAT -> new KnnVectorQuery(name(), queryVector, numCands, filter);
};
} }
} }
@ -628,21 +843,7 @@ public class DenseVectorFieldMapper extends FieldMapper {
} }
private Field parseKnnVector(DocumentParserContext context) throws IOException { private Field parseKnnVector(DocumentParserContext context) throws IOException {
float[] vector = new float[dims]; return elementType.parseKnnVector(context, this);
float squaredMagnitude = 0.0f;
int index = 0;
for (Token token = context.parser().nextToken(); token != Token.END_ARRAY; token = context.parser().nextToken()) {
checkDimensionExceeded(index, context);
ensureExpectedToken(Token.VALUE_NUMBER, token, context.parser());
float value = context.parser().floatValue(true);
vector[index++] = value;
squaredMagnitude += value * value;
}
checkDimensionMatches(index, context);
elementType.checkVectorBounds(vector);
elementType.checkVectorMagnitude(similarity, vector, squaredMagnitude);
return elementType.createKnnVectorField(fieldType().name(), vector, similarity.function);
} }
private Field parseBinaryDocValuesVector(DocumentParserContext context) throws IOException { private Field parseBinaryDocValuesVector(DocumentParserContext context) throws IOException {
@ -653,22 +854,7 @@ public class DenseVectorFieldMapper extends FieldMapper {
: new byte[dims * elementType.elementBytes]; : new byte[dims * elementType.elementBytes];
ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
double dotProduct = 0f; double dotProduct = elementType.parseKnnVectorToByteBuffer(context, this, byteBuffer);
int index = 0;
float[] vector = new float[dims];
for (Token token = context.parser().nextToken(); token != Token.END_ARRAY; token = context.parser().nextToken()) {
checkDimensionExceeded(index, context);
ensureExpectedToken(Token.VALUE_NUMBER, token, context.parser());
float value = context.parser().floatValue(true);
vector[index] = value;
elementType.writeValue(byteBuffer, value);
dotProduct += value * value;
index++;
}
checkDimensionMatches(index, context);
elementType.checkVectorBounds(vector);
if (indexCreatedVersion.onOrAfter(Version.V_7_5_0)) { if (indexCreatedVersion.onOrAfter(Version.V_7_5_0)) {
// encode vector magnitude at the end // encode vector magnitude at the end
float vectorMagnitude = (float) Math.sqrt(dotProduct); float vectorMagnitude = (float) Math.sqrt(dotProduct);
@ -759,7 +945,7 @@ public class DenseVectorFieldMapper extends FieldMapper {
return null; // use default format return null; // use default format
} else { } else {
HnswIndexOptions hnswIndexOptions = (HnswIndexOptions) indexOptions; HnswIndexOptions hnswIndexOptions = (HnswIndexOptions) indexOptions;
return new Lucene94HnswVectorsFormat(hnswIndexOptions.m, hnswIndexOptions.efConstruction); return new Lucene95HnswVectorsFormat(hnswIndexOptions.m, hnswIndexOptions.efConstruction);
} }
} }
@ -778,6 +964,7 @@ public class DenseVectorFieldMapper extends FieldMapper {
private class IndexedSyntheticFieldLoader implements SourceLoader.SyntheticFieldLoader { private class IndexedSyntheticFieldLoader implements SourceLoader.SyntheticFieldLoader {
private VectorValues values; private VectorValues values;
private ByteVectorValues byteVectorValues;
private boolean hasValue; private boolean hasValue;
@Override @Override
@ -788,13 +975,20 @@ public class DenseVectorFieldMapper extends FieldMapper {
@Override @Override
public DocValuesLoader docValuesLoader(LeafReader leafReader, int[] docIdsInLeaf) throws IOException { public DocValuesLoader docValuesLoader(LeafReader leafReader, int[] docIdsInLeaf) throws IOException {
values = leafReader.getVectorValues(name()); values = leafReader.getVectorValues(name());
if (values == null) { if (values != null) {
return null; return docId -> {
hasValue = docId == values.advance(docId);
return hasValue;
};
} }
return docId -> { byteVectorValues = leafReader.getByteVectorValues(name());
hasValue = docId == values.advance(docId); if (byteVectorValues != null) {
return hasValue; return docId -> {
}; hasValue = docId == byteVectorValues.advance(docId);
return hasValue;
};
}
return null;
} }
@Override @Override
@ -808,8 +1002,15 @@ public class DenseVectorFieldMapper extends FieldMapper {
return; return;
} }
b.startArray(simpleName()); b.startArray(simpleName());
for (float v : values.vectorValue()) { if (values != null) {
b.value(v); for (float v : values.vectorValue()) {
b.value(v);
}
} else if (byteVectorValues != null) {
BytesRef vectorValue = byteVectorValues.vectorValue();
for (int i = vectorValue.offset; i < vectorValue.offset + vectorValue.length; i++) {
b.value(vectorValue.bytes[i]);
}
} }
b.endArray(); b.endArray();
} }
@ -850,7 +1051,7 @@ public class DenseVectorFieldMapper extends FieldMapper {
BytesRef ref = values.binaryValue(); BytesRef ref = values.binaryValue();
ByteBuffer byteBuffer = ByteBuffer.wrap(ref.bytes, ref.offset, ref.length); ByteBuffer byteBuffer = ByteBuffer.wrap(ref.bytes, ref.offset, ref.length);
for (int dim = 0; dim < dims; dim++) { for (int dim = 0; dim < dims; dim++) {
b.value(elementType.readValue(byteBuffer)); elementType.readAndWriteValue(byteBuffer, b);
} }
b.endArray(); b.endArray();
} }

View file

@ -11,7 +11,6 @@ package org.elasticsearch.index.mapper.vectors;
import org.apache.lucene.index.BinaryDocValues; import org.apache.lucene.index.BinaryDocValues;
import org.apache.lucene.index.DocValues; import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.LeafReader; import org.apache.lucene.index.LeafReader;
import org.apache.lucene.index.VectorValues;
import org.elasticsearch.Version; import org.elasticsearch.Version;
import org.elasticsearch.index.fielddata.LeafFieldData; import org.elasticsearch.index.fielddata.LeafFieldData;
import org.elasticsearch.index.fielddata.SortedBinaryDocValues; import org.elasticsearch.index.fielddata.SortedBinaryDocValues;
@ -56,15 +55,9 @@ final class VectorDVLeafFieldData implements LeafFieldData {
public DocValuesScriptFieldFactory getScriptFieldFactory(String name) { public DocValuesScriptFieldFactory getScriptFieldFactory(String name) {
try { try {
if (indexed) { if (indexed) {
VectorValues values = reader.getVectorValues(field);
if (values == VectorValues.EMPTY) {
// There's no way for KnnDenseVectorDocValuesField to reliably differentiate between VectorValues.EMPTY and
// values that can be iterated through. Since VectorValues.EMPTY throws on docID(), pass a null instead.
values = null;
}
return switch (elementType) { return switch (elementType) {
case BYTE -> new ByteKnnDenseVectorDocValuesField(values, name, elementType, dims); case BYTE -> new ByteKnnDenseVectorDocValuesField(reader.getByteVectorValues(field), name, dims);
case FLOAT -> new KnnDenseVectorDocValuesField(values, name, elementType, dims); case FLOAT -> new KnnDenseVectorDocValuesField(reader.getVectorValues(field), name, dims);
}; };
} else { } else {
BinaryDocValues values = DocValues.getBinary(reader, field); BinaryDocValues values = DocValues.getBinary(reader, field);

View file

@ -407,11 +407,11 @@ public class CombinedFieldsQueryBuilder extends AbstractQueryBuilder<CombinedFie
} }
@Override @Override
protected Query newSynonymQuery(TermAndBoost[] terms) { protected Query newSynonymQuery(String field, TermAndBoost[] terms) {
CombinedFieldQuery.Builder query = new CombinedFieldQuery.Builder(); CombinedFieldQuery.Builder query = new CombinedFieldQuery.Builder();
for (TermAndBoost termAndBoost : terms) { for (TermAndBoost termAndBoost : terms) {
assert termAndBoost.boost == BoostAttribute.DEFAULT_BOOST; assert termAndBoost.boost == BoostAttribute.DEFAULT_BOOST;
BytesRef bytes = termAndBoost.term.bytes(); BytesRef bytes = termAndBoost.term;
query.addTerm(bytes); query.addTerm(bytes);
} }
for (FieldAndBoost fieldAndBoost : fields) { for (FieldAndBoost fieldAndBoost : fields) {
@ -424,8 +424,8 @@ public class CombinedFieldsQueryBuilder extends AbstractQueryBuilder<CombinedFie
@Override @Override
protected Query newTermQuery(Term term, float boost) { protected Query newTermQuery(Term term, float boost) {
TermAndBoost termAndBoost = new TermAndBoost(term, boost); TermAndBoost termAndBoost = new TermAndBoost(term.bytes(), boost);
return newSynonymQuery(new TermAndBoost[] { termAndBoost }); return newSynonymQuery(term.field(), new TermAndBoost[] { termAndBoost });
} }
@Override @Override

View file

@ -538,9 +538,9 @@ public class MatchQueryParser {
} else { } else {
// We don't apply prefix on synonyms // We don't apply prefix on synonyms
final TermAndBoost[] termAndBoosts = current.stream() final TermAndBoost[] termAndBoosts = current.stream()
.map(t -> new TermAndBoost(t, BoostAttribute.DEFAULT_BOOST)) .map(t -> new TermAndBoost(t.bytes(), BoostAttribute.DEFAULT_BOOST))
.toArray(TermAndBoost[]::new); .toArray(TermAndBoost[]::new);
q.add(newSynonymQuery(termAndBoosts), operator); q.add(newSynonymQuery(field, termAndBoosts), operator);
} }
} }
@ -648,9 +648,9 @@ public class MatchQueryParser {
} else { } else {
// We don't apply prefix on synonyms // We don't apply prefix on synonyms
final TermAndBoost[] termAndBoosts = Arrays.stream(terms) final TermAndBoost[] termAndBoosts = Arrays.stream(terms)
.map(t -> new TermAndBoost(t, BoostAttribute.DEFAULT_BOOST)) .map(t -> new TermAndBoost(t.bytes(), BoostAttribute.DEFAULT_BOOST))
.toArray(TermAndBoost[]::new); .toArray(TermAndBoost[]::new);
queryPos = newSynonymQuery(termAndBoosts); queryPos = newSynonymQuery(field, termAndBoosts);
} }
} }
if (queryPos != null) { if (queryPos != null) {

View file

@ -196,10 +196,10 @@ public class MultiMatchQueryParser extends MatchQueryParser {
} }
@Override @Override
protected Query newSynonymQuery(TermAndBoost[] terms) { protected Query newSynonymQuery(String field, TermAndBoost[] terms) {
BytesRef[] values = new BytesRef[terms.length]; BytesRef[] values = new BytesRef[terms.length];
for (int i = 0; i < terms.length; i++) { for (int i = 0; i < terms.length; i++) {
values[i] = terms[i].term.bytes(); values[i] = terms[i].term;
} }
return blendTerms(context, values, tieBreaker, lenient, blendedFields); return blendTerms(context, values, tieBreaker, lenient, blendedFields);
} }

View file

@ -52,18 +52,18 @@ public class VectorScoreScriptUtils {
public ByteDenseVectorFunction(ScoreScript scoreScript, DenseVectorDocValuesField field, List<Number> queryVector) { public ByteDenseVectorFunction(ScoreScript scoreScript, DenseVectorDocValuesField field, List<Number> queryVector) {
super(scoreScript, field); super(scoreScript, field);
DenseVector.checkDimensions(field.get().getDims(), queryVector.size()); DenseVector.checkDimensions(field.get().getDims(), queryVector.size());
float[] vector = new float[queryVector.size()];
this.queryVector = new byte[queryVector.size()]; this.queryVector = new byte[queryVector.size()];
float[] validateValues = new float[queryVector.size()];
int queryMagnitude = 0; int queryMagnitude = 0;
for (int i = 0; i < queryVector.size(); i++) { for (int i = 0; i < queryVector.size(); i++) {
float value = queryVector.get(i).floatValue(); final Number number = queryVector.get(i);
vector[i] = value; byte value = number.byteValue();
this.queryVector[i] = (byte) value; this.queryVector[i] = value;
queryMagnitude += value * value; queryMagnitude += value * value;
validateValues[i] = number.floatValue();
} }
this.qvMagnitude = (float) Math.sqrt(queryMagnitude); this.qvMagnitude = (float) Math.sqrt(queryMagnitude);
field.getElementType().checkVectorBounds(vector); field.getElementType().checkVectorBounds(validateValues);
} }
} }

View file

@ -27,6 +27,7 @@ public class ByteKnnDenseVector implements DenseVector {
@Override @Override
public float[] getVector() { public float[] getVector() {
// TODO it would be really nice if we didn't transform the `byte[]` arrays to `float[]`
if (floatDocVector == null) { if (floatDocVector == null) {
floatDocVector = new float[docVector.length]; floatDocVector = new float[docVector.length];

View file

@ -8,7 +8,7 @@
package org.elasticsearch.script.field.vectors; package org.elasticsearch.script.field.vectors;
import org.apache.lucene.index.VectorValues; import org.apache.lucene.index.ByteVectorValues;
import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRef;
import org.elasticsearch.core.Nullable; import org.elasticsearch.core.Nullable;
import org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper.ElementType; import org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper.ElementType;
@ -19,12 +19,12 @@ import java.io.IOException;
import static org.apache.lucene.search.DocIdSetIterator.NO_MORE_DOCS; import static org.apache.lucene.search.DocIdSetIterator.NO_MORE_DOCS;
public class ByteKnnDenseVectorDocValuesField extends DenseVectorDocValuesField { public class ByteKnnDenseVectorDocValuesField extends DenseVectorDocValuesField {
protected VectorValues input; // null if no vectors protected ByteVectorValues input; // null if no vectors
protected BytesRef vector; protected BytesRef vector;
protected final int dims; protected final int dims;
public ByteKnnDenseVectorDocValuesField(@Nullable VectorValues input, String name, ElementType elementType, int dims) { public ByteKnnDenseVectorDocValuesField(@Nullable ByteVectorValues input, String name, int dims) {
super(name, elementType); super(name, ElementType.BYTE);
this.dims = dims; this.dims = dims;
this.input = input; this.input = input;
} }
@ -38,11 +38,11 @@ public class ByteKnnDenseVectorDocValuesField extends DenseVectorDocValuesField
if (currentDoc == NO_MORE_DOCS || docId < currentDoc) { if (currentDoc == NO_MORE_DOCS || docId < currentDoc) {
vector = null; vector = null;
} else if (docId == currentDoc) { } else if (docId == currentDoc) {
vector = input.binaryValue(); vector = input.vectorValue();
} else { } else {
currentDoc = input.advance(docId); currentDoc = input.advance(docId);
if (currentDoc == docId) { if (currentDoc == docId) {
vector = input.binaryValue(); vector = input.vectorValue();
} else { } else {
vector = null; vector = null;
} }

View file

@ -22,8 +22,8 @@ public class KnnDenseVectorDocValuesField extends DenseVectorDocValuesField {
protected float[] vector; protected float[] vector;
protected final int dims; protected final int dims;
public KnnDenseVectorDocValuesField(@Nullable VectorValues input, String name, ElementType elementType, int dims) { public KnnDenseVectorDocValuesField(@Nullable VectorValues input, String name, int dims) {
super(name, elementType); super(name, ElementType.FLOAT);
this.dims = dims; this.dims = dims;
this.input = input; this.input = input;
} }

View file

@ -9,13 +9,13 @@
package org.elasticsearch.search.aggregations.bucket.filter; package org.elasticsearch.search.aggregations.bucket.filter;
import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.sandbox.search.IndexSortSortedNumericDocValuesRangeQuery;
import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.BulkScorer; import org.apache.lucene.search.BulkScorer;
import org.apache.lucene.search.ConstantScoreQuery; import org.apache.lucene.search.ConstantScoreQuery;
import org.apache.lucene.search.IndexOrDocValuesQuery; import org.apache.lucene.search.IndexOrDocValuesQuery;
import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.IndexSortSortedNumericDocValuesRangeQuery;
import org.apache.lucene.search.LeafCollector; import org.apache.lucene.search.LeafCollector;
import org.apache.lucene.search.PointRangeQuery; import org.apache.lucene.search.PointRangeQuery;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;

View file

@ -9,6 +9,7 @@
package org.elasticsearch.search.internal; package org.elasticsearch.search.internal;
import org.apache.lucene.codecs.StoredFieldsReader; import org.apache.lucene.codecs.StoredFieldsReader;
import org.apache.lucene.index.ByteVectorValues;
import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.FilterDirectoryReader; import org.apache.lucene.index.FilterDirectoryReader;
import org.apache.lucene.index.FilterLeafReader; import org.apache.lucene.index.FilterLeafReader;
@ -126,6 +127,45 @@ class ExitableDirectoryReader extends FilterDirectoryReader {
return reader; return reader;
} }
@Override
public ByteVectorValues getByteVectorValues(String field) throws IOException {
ByteVectorValues vectorValues = in.getByteVectorValues(field);
if (vectorValues == null) {
return null;
}
return queryCancellation.isEnabled() ? new ExitableByteVectorValues(queryCancellation, vectorValues) : vectorValues;
}
@Override
public TopDocs searchNearestVectors(String field, BytesRef target, int k, Bits acceptDocs, int visitedLimit) throws IOException {
if (queryCancellation.isEnabled() == false) {
return in.searchNearestVectors(field, target, k, acceptDocs, visitedLimit);
}
// when acceptDocs is null due to no doc deleted, we will instantiate a new one that would
// match all docs to allow timeout checking.
final Bits updatedAcceptDocs = acceptDocs == null ? new Bits.MatchAllBits(maxDoc()) : acceptDocs;
Bits timeoutCheckingAcceptDocs = new Bits() {
private static final int MAX_CALLS_BEFORE_QUERY_TIMEOUT_CHECK = 10;
private int calls;
@Override
public boolean get(int index) {
if (calls++ % MAX_CALLS_BEFORE_QUERY_TIMEOUT_CHECK == 0) {
queryCancellation.checkCancelled();
}
return updatedAcceptDocs.get(index);
}
@Override
public int length() {
return updatedAcceptDocs.length();
}
};
return in.searchNearestVectors(field, target, k, timeoutCheckingAcceptDocs, visitedLimit);
}
@Override @Override
public VectorValues getVectorValues(String field) throws IOException { public VectorValues getVectorValues(String field) throws IOException {
VectorValues vectorValues = in.getVectorValues(field); VectorValues vectorValues = in.getVectorValues(field);
@ -433,6 +473,57 @@ class ExitableDirectoryReader extends FilterDirectoryReader {
} }
} }
private static class ExitableByteVectorValues extends ByteVectorValues {
private int calls;
private final QueryCancellation queryCancellation;
private final ByteVectorValues in;
private ExitableByteVectorValues(QueryCancellation queryCancellation, ByteVectorValues in) {
this.queryCancellation = queryCancellation;
this.in = in;
}
@Override
public int dimension() {
return in.dimension();
}
@Override
public int size() {
return in.size();
}
@Override
public BytesRef vectorValue() throws IOException {
return in.vectorValue();
}
@Override
public int docID() {
return in.docID();
}
@Override
public int nextDoc() throws IOException {
final int nextDoc = in.nextDoc();
checkAndThrowWithSampling();
return nextDoc;
}
@Override
public int advance(int target) throws IOException {
final int advance = in.advance(target);
checkAndThrowWithSampling();
return advance;
}
private void checkAndThrowWithSampling() {
if ((calls++ & ExitableIntersectVisitor.MAX_CALLS_BEFORE_QUERY_TIMEOUT_CHECK) == 0) {
this.queryCancellation.checkCancelled();
}
}
}
private static class ExitableVectorValues extends FilterVectorValues { private static class ExitableVectorValues extends FilterVectorValues {
private int calls; private int calls;
private final QueryCancellation queryCancellation; private final QueryCancellation queryCancellation;

View file

@ -10,6 +10,7 @@ package org.elasticsearch.search.internal;
import org.apache.lucene.codecs.StoredFieldsReader; import org.apache.lucene.codecs.StoredFieldsReader;
import org.apache.lucene.index.BinaryDocValues; import org.apache.lucene.index.BinaryDocValues;
import org.apache.lucene.index.ByteVectorValues;
import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.FieldInfo; import org.apache.lucene.index.FieldInfo;
import org.apache.lucene.index.Fields; import org.apache.lucene.index.Fields;
@ -23,6 +24,8 @@ import org.apache.lucene.index.SortedDocValues;
import org.apache.lucene.index.SortedNumericDocValues; import org.apache.lucene.index.SortedNumericDocValues;
import org.apache.lucene.index.SortedSetDocValues; import org.apache.lucene.index.SortedSetDocValues;
import org.apache.lucene.index.StoredFieldVisitor; import org.apache.lucene.index.StoredFieldVisitor;
import org.apache.lucene.index.StoredFields;
import org.apache.lucene.index.TermVectors;
import org.apache.lucene.index.Terms; import org.apache.lucene.index.Terms;
import org.apache.lucene.index.TermsEnum; import org.apache.lucene.index.TermsEnum;
import org.apache.lucene.index.VectorValues; import org.apache.lucene.index.VectorValues;
@ -108,6 +111,21 @@ public class FieldUsageTrackingDirectoryReader extends FilterDirectoryReader {
return f; return f;
} }
@Override
public TermVectors termVectors() throws IOException {
TermVectors termVectors = super.termVectors();
return new TermVectors() {
@Override
public Fields get(int doc) throws IOException {
Fields f = termVectors.get(doc);
if (f != null) {
f = new FieldUsageTrackingTermVectorFields(f);
}
return f;
}
};
}
@Override @Override
public PointValues getPointValues(String field) throws IOException { public PointValues getPointValues(String field) throws IOException {
PointValues pointValues = super.getPointValues(field); PointValues pointValues = super.getPointValues(field);
@ -126,6 +144,21 @@ public class FieldUsageTrackingDirectoryReader extends FilterDirectoryReader {
} }
} }
@Override
public StoredFields storedFields() throws IOException {
StoredFields storedFields = super.storedFields();
return new StoredFields() {
@Override
public void document(int docID, StoredFieldVisitor visitor) throws IOException {
if (visitor instanceof FieldNamesProvidingStoredFieldsVisitor) {
storedFields.document(docID, new FieldUsageFieldsVisitor((FieldNamesProvidingStoredFieldsVisitor) visitor));
} else {
storedFields.document(docID, new FieldUsageStoredFieldVisitor(visitor));
}
}
};
}
@Override @Override
public Terms terms(String field) throws IOException { public Terms terms(String field) throws IOException {
Terms terms = super.terms(field); Terms terms = super.terms(field);
@ -195,6 +228,24 @@ public class FieldUsageTrackingDirectoryReader extends FilterDirectoryReader {
return vectorValues; return vectorValues;
} }
@Override
public ByteVectorValues getByteVectorValues(String field) throws IOException {
ByteVectorValues vectorValues = super.getByteVectorValues(field);
if (vectorValues != null) {
notifier.onKnnVectorsUsed(field);
}
return vectorValues;
}
@Override
public TopDocs searchNearestVectors(String field, BytesRef target, int k, Bits acceptDocs, int visitedLimit) throws IOException {
TopDocs topDocs = super.searchNearestVectors(field, target, k, acceptDocs, visitedLimit);
if (topDocs != null) {
notifier.onKnnVectorsUsed(field);
}
return topDocs;
}
@Override @Override
public TopDocs searchNearestVectors(String field, float[] target, int k, Bits acceptDocs, int visitedLimit) throws IOException { public TopDocs searchNearestVectors(String field, float[] target, int k, Bits acceptDocs, int visitedLimit) throws IOException {
TopDocs topDocs = super.searchNearestVectors(field, target, k, acceptDocs, visitedLimit); TopDocs topDocs = super.searchNearestVectors(field, target, k, acceptDocs, visitedLimit);
@ -223,8 +274,8 @@ public class FieldUsageTrackingDirectoryReader extends FilterDirectoryReader {
} }
@Override @Override
public void visitDocument(int docID, StoredFieldVisitor visitor) throws IOException { public void document(int docID, StoredFieldVisitor visitor) throws IOException {
reader.visitDocument(docID, new FieldUsageStoredFieldVisitor(visitor)); reader.document(docID, new FieldUsageStoredFieldVisitor(visitor));
} }
@Override @Override

View file

@ -44,6 +44,7 @@ public class KnnSearchBuilder implements Writeable, ToXContentFragment, Rewritea
private static final ConstructingObjectParser<KnnSearchBuilder, Void> PARSER = new ConstructingObjectParser<>("knn", args -> { private static final ConstructingObjectParser<KnnSearchBuilder, Void> PARSER = new ConstructingObjectParser<>("knn", args -> {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
// TODO optimize parsing for when BYTE values are provided
List<Float> vector = (List<Float>) args[1]; List<Float> vector = (List<Float>) args[1];
float[] vectorArray = new float[vector.size()]; float[] vectorArray = new float[vector.size()];
for (int i = 0; i < vector.size(); i++) { for (int i = 0; i < vector.size(); i++) {

View file

@ -12,9 +12,11 @@ import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.KnnVectorQuery; import org.apache.lucene.search.KnnVectorQuery;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.apache.lucene.util.BytesRef;
import org.elasticsearch.Version; import org.elasticsearch.Version;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.core.Nullable;
import org.elasticsearch.index.mapper.MappedFieldType; import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper; import org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper;
import org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper.DenseVectorFieldType; import org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper.DenseVectorFieldType;
@ -41,12 +43,22 @@ public class KnnVectorQueryBuilder extends AbstractQueryBuilder<KnnVectorQueryBu
private final String fieldName; private final String fieldName;
private final float[] queryVector; private final float[] queryVector;
private final byte[] byteQueryVector;
private final int numCands; private final int numCands;
private final List<QueryBuilder> filterQueries; private final List<QueryBuilder> filterQueries;
public KnnVectorQueryBuilder(String fieldName, float[] queryVector, int numCands) { public KnnVectorQueryBuilder(String fieldName, float[] queryVector, int numCands) {
this.fieldName = fieldName; this.fieldName = fieldName;
this.queryVector = queryVector; this.queryVector = Objects.requireNonNull(queryVector);
this.byteQueryVector = null;
this.numCands = numCands;
this.filterQueries = new ArrayList<>();
}
public KnnVectorQueryBuilder(String fieldName, byte[] queryVector, int numCands) {
this.fieldName = fieldName;
this.queryVector = null;
this.byteQueryVector = Objects.requireNonNull(queryVector);
this.numCands = numCands; this.numCands = numCands;
this.filterQueries = new ArrayList<>(); this.filterQueries = new ArrayList<>();
} }
@ -55,7 +67,13 @@ public class KnnVectorQueryBuilder extends AbstractQueryBuilder<KnnVectorQueryBu
super(in); super(in);
this.fieldName = in.readString(); this.fieldName = in.readString();
this.numCands = in.readVInt(); this.numCands = in.readVInt();
this.queryVector = in.readFloatArray(); if (in.getVersion().before(Version.V_8_7_0)) {
this.queryVector = in.readFloatArray();
this.byteQueryVector = null;
} else {
this.queryVector = in.readBoolean() ? in.readFloatArray() : null;
this.byteQueryVector = in.readBoolean() ? in.readByteArray() : null;
}
if (in.getVersion().before(Version.V_8_2_0)) { if (in.getVersion().before(Version.V_8_2_0)) {
this.filterQueries = new ArrayList<>(); this.filterQueries = new ArrayList<>();
} else { } else {
@ -67,10 +85,16 @@ public class KnnVectorQueryBuilder extends AbstractQueryBuilder<KnnVectorQueryBu
return fieldName; return fieldName;
} }
@Nullable
public float[] queryVector() { public float[] queryVector() {
return queryVector; return queryVector;
} }
@Nullable
public byte[] getByteQueryVector() {
return byteQueryVector;
}
public int numCands() { public int numCands() {
return numCands; return numCands;
} }
@ -95,7 +119,29 @@ public class KnnVectorQueryBuilder extends AbstractQueryBuilder<KnnVectorQueryBu
protected void doWriteTo(StreamOutput out) throws IOException { protected void doWriteTo(StreamOutput out) throws IOException {
out.writeString(fieldName); out.writeString(fieldName);
out.writeVInt(numCands); out.writeVInt(numCands);
out.writeFloatArray(queryVector); if (out.getVersion().onOrAfter(Version.V_8_7_0)) {
boolean queryVectorNotNull = queryVector != null;
out.writeBoolean(queryVectorNotNull);
if (queryVectorNotNull) {
out.writeFloatArray(queryVector);
}
boolean byteVectorNotNull = byteQueryVector != null;
out.writeBoolean(byteVectorNotNull);
if (byteVectorNotNull) {
out.writeByteArray(byteQueryVector);
}
} else {
final float[] f;
if (queryVector != null) {
f = queryVector;
} else {
f = new float[byteQueryVector.length];
for (int i = 0; i < byteQueryVector.length; i++) {
f[i] = byteQueryVector[i];
}
}
out.writeFloatArray(f);
}
if (out.getVersion().onOrAfter(Version.V_8_2_0)) { if (out.getVersion().onOrAfter(Version.V_8_2_0)) {
writeQueries(out, filterQueries); writeQueries(out, filterQueries);
} }
@ -103,7 +149,10 @@ public class KnnVectorQueryBuilder extends AbstractQueryBuilder<KnnVectorQueryBu
@Override @Override
protected void doXContent(XContentBuilder builder, Params params) throws IOException { protected void doXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(NAME).field("field", fieldName).field("vector", queryVector).field("num_candidates", numCands); builder.startObject(NAME)
.field("field", fieldName)
.field("vector", queryVector != null ? queryVector : byteQueryVector)
.field("num_candidates", numCands);
if (filterQueries.isEmpty() == false) { if (filterQueries.isEmpty() == false) {
builder.startArray("filters"); builder.startArray("filters");
for (QueryBuilder filterQuery : filterQueries) { for (QueryBuilder filterQuery : filterQueries) {
@ -135,7 +184,9 @@ public class KnnVectorQueryBuilder extends AbstractQueryBuilder<KnnVectorQueryBu
rewrittenQueries.add(rewrittenQuery); rewrittenQueries.add(rewrittenQuery);
} }
if (changed) { if (changed) {
return new KnnVectorQueryBuilder(fieldName, queryVector, numCands).addFilterQueries(rewrittenQueries); return byteQueryVector != null
? new KnnVectorQueryBuilder(fieldName, byteQueryVector, numCands).addFilterQueries(rewrittenQueries)
: new KnnVectorQueryBuilder(fieldName, queryVector, numCands).addFilterQueries(rewrittenQueries);
} }
return this; return this;
} }
@ -161,18 +212,21 @@ public class KnnVectorQueryBuilder extends AbstractQueryBuilder<KnnVectorQueryBu
Query filterQuery = booleanQuery.clauses().isEmpty() ? null : booleanQuery; Query filterQuery = booleanQuery.clauses().isEmpty() ? null : booleanQuery;
DenseVectorFieldType vectorFieldType = (DenseVectorFieldType) fieldType; DenseVectorFieldType vectorFieldType = (DenseVectorFieldType) fieldType;
return vectorFieldType.createKnnQuery(queryVector, numCands, filterQuery); return queryVector != null
? vectorFieldType.createKnnQuery(queryVector, numCands, filterQuery)
: vectorFieldType.createKnnQuery(new BytesRef(byteQueryVector), numCands, filterQuery);
} }
@Override @Override
protected int doHashCode() { protected int doHashCode() {
return Objects.hash(fieldName, Arrays.hashCode(queryVector), numCands, filterQueries); return Objects.hash(fieldName, Arrays.hashCode(queryVector), Arrays.hashCode(byteQueryVector), numCands, filterQueries);
} }
@Override @Override
protected boolean doEquals(KnnVectorQueryBuilder other) { protected boolean doEquals(KnnVectorQueryBuilder other) {
return Objects.equals(fieldName, other.fieldName) return Objects.equals(fieldName, other.fieldName)
&& Arrays.equals(queryVector, other.queryVector) && Arrays.equals(queryVector, other.queryVector)
&& Arrays.equals(byteQueryVector, other.byteQueryVector)
&& numCands == other.numCands && numCands == other.numCands
&& Objects.equals(filterQueries, other.filterQueries); && Objects.equals(filterQueries, other.filterQueries);
} }

View file

@ -13,8 +13,8 @@ import org.apache.lucene.codecs.KnnVectorsFormat;
import org.apache.lucene.codecs.PostingsFormat; import org.apache.lucene.codecs.PostingsFormat;
import org.apache.lucene.codecs.lucene90.Lucene90DocValuesFormat; import org.apache.lucene.codecs.lucene90.Lucene90DocValuesFormat;
import org.apache.lucene.codecs.lucene90.Lucene90PostingsFormat; import org.apache.lucene.codecs.lucene90.Lucene90PostingsFormat;
import org.apache.lucene.codecs.lucene94.Lucene94Codec; import org.apache.lucene.codecs.lucene95.Lucene95Codec;
import org.apache.lucene.codecs.lucene94.Lucene94HnswVectorsFormat; import org.apache.lucene.codecs.lucene95.Lucene95HnswVectorsFormat;
import org.apache.lucene.codecs.perfield.PerFieldDocValuesFormat; import org.apache.lucene.codecs.perfield.PerFieldDocValuesFormat;
import org.apache.lucene.codecs.perfield.PerFieldKnnVectorsFormat; import org.apache.lucene.codecs.perfield.PerFieldKnnVectorsFormat;
import org.apache.lucene.codecs.perfield.PerFieldPostingsFormat; import org.apache.lucene.codecs.perfield.PerFieldPostingsFormat;
@ -80,6 +80,7 @@ import java.util.function.Consumer;
import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.greaterThanOrEqualTo; import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.notNullValue;
@ -261,9 +262,11 @@ public class IndexDiskUsageAnalyzerTests extends ESTestCase {
final IndexDiskUsageStats stats = IndexDiskUsageAnalyzer.analyze(testShardId(), lastCommit(dir), () -> {}); final IndexDiskUsageStats stats = IndexDiskUsageAnalyzer.analyze(testShardId(), lastCommit(dir), () -> {});
logger.info("--> stats {}", stats); logger.info("--> stats {}", stats);
int dataBytes = numDocs * dimension * Float.BYTES; // size of flat vector data long dataBytes = (long) numDocs * dimension * Float.BYTES; // size of flat vector data
int indexBytesEstimate = numDocs * Integer.BYTES * Lucene94HnswVectorsFormat.DEFAULT_MAX_CONN * 2; // rough size of HNSW graph long indexBytesEstimate = (long) numDocs * (Lucene95HnswVectorsFormat.DEFAULT_MAX_CONN / 2); // rough size of HNSW graph
assertTrue(stats.total().getKnnVectorsBytes() > dataBytes + indexBytesEstimate); assertThat(stats.total().getKnnVectorsBytes(), greaterThan(dataBytes));
long connectionOverhead = stats.total().getKnnVectorsBytes() - dataBytes;
assertThat(connectionOverhead, greaterThan(indexBytesEstimate));
} }
} }
@ -323,7 +326,7 @@ public class IndexDiskUsageAnalyzerTests extends ESTestCase {
public void testCompletionField() throws Exception { public void testCompletionField() throws Exception {
IndexWriterConfig config = new IndexWriterConfig().setCommitOnClose(true) IndexWriterConfig config = new IndexWriterConfig().setCommitOnClose(true)
.setUseCompoundFile(false) .setUseCompoundFile(false)
.setCodec(new Lucene94Codec(Lucene94Codec.Mode.BEST_SPEED) { .setCodec(new Lucene95Codec(Lucene95Codec.Mode.BEST_SPEED) {
@Override @Override
public PostingsFormat getPostingsFormatForField(String field) { public PostingsFormat getPostingsFormatForField(String field) {
if (field.startsWith("suggest_")) { if (field.startsWith("suggest_")) {
@ -410,25 +413,25 @@ public class IndexDiskUsageAnalyzerTests extends ESTestCase {
enum CodecMode { enum CodecMode {
BEST_SPEED { BEST_SPEED {
@Override @Override
Lucene94Codec.Mode mode() { Lucene95Codec.Mode mode() {
return Lucene94Codec.Mode.BEST_SPEED; return Lucene95Codec.Mode.BEST_SPEED;
} }
}, },
BEST_COMPRESSION { BEST_COMPRESSION {
@Override @Override
Lucene94Codec.Mode mode() { Lucene95Codec.Mode mode() {
return Lucene94Codec.Mode.BEST_COMPRESSION; return Lucene95Codec.Mode.BEST_COMPRESSION;
} }
}; };
abstract Lucene94Codec.Mode mode(); abstract Lucene95Codec.Mode mode();
} }
static void indexRandomly(Directory directory, CodecMode codecMode, int numDocs, Consumer<Document> addFields) throws IOException { static void indexRandomly(Directory directory, CodecMode codecMode, int numDocs, Consumer<Document> addFields) throws IOException {
IndexWriterConfig config = new IndexWriterConfig().setCommitOnClose(true) IndexWriterConfig config = new IndexWriterConfig().setCommitOnClose(true)
.setUseCompoundFile(randomBoolean()) .setUseCompoundFile(randomBoolean())
.setCodec(new Lucene94Codec(codecMode.mode())); .setCodec(new Lucene95Codec(codecMode.mode()));
try (IndexWriter writer = new IndexWriter(directory, config)) { try (IndexWriter writer = new IndexWriter(directory, config)) {
for (int i = 0; i < numDocs; i++) { for (int i = 0; i < numDocs; i++) {
final Document doc = new Document(); final Document doc = new Document();
@ -636,7 +639,7 @@ public class IndexDiskUsageAnalyzerTests extends ESTestCase {
try (DirectoryReader reader = DirectoryReader.open(source)) { try (DirectoryReader reader = DirectoryReader.open(source)) {
IndexWriterConfig config = new IndexWriterConfig().setSoftDeletesField(Lucene.SOFT_DELETES_FIELD) IndexWriterConfig config = new IndexWriterConfig().setSoftDeletesField(Lucene.SOFT_DELETES_FIELD)
.setUseCompoundFile(randomBoolean()) .setUseCompoundFile(randomBoolean())
.setCodec(new Lucene94Codec(mode.mode()) { .setCodec(new Lucene95Codec(mode.mode()) {
@Override @Override
public PostingsFormat getPostingsFormatForField(String field) { public PostingsFormat getPostingsFormatForField(String field) {
return new Lucene90PostingsFormat(); return new Lucene90PostingsFormat();
@ -649,7 +652,7 @@ public class IndexDiskUsageAnalyzerTests extends ESTestCase {
@Override @Override
public KnnVectorsFormat getKnnVectorsFormatForField(String field) { public KnnVectorsFormat getKnnVectorsFormatForField(String field) {
return new Lucene94HnswVectorsFormat(); return new Lucene95HnswVectorsFormat();
} }
@Override @Override

View file

@ -10,7 +10,7 @@ package org.elasticsearch.index.codec;
import org.apache.lucene.codecs.Codec; import org.apache.lucene.codecs.Codec;
import org.apache.lucene.codecs.lucene90.Lucene90StoredFieldsFormat; import org.apache.lucene.codecs.lucene90.Lucene90StoredFieldsFormat;
import org.apache.lucene.codecs.lucene94.Lucene94Codec; import org.apache.lucene.codecs.lucene95.Lucene95Codec;
import org.apache.lucene.document.Document; import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.IndexWriter;
@ -42,21 +42,21 @@ public class CodecTests extends ESTestCase {
public void testResolveDefaultCodecs() throws Exception { public void testResolveDefaultCodecs() throws Exception {
CodecService codecService = createCodecService(); CodecService codecService = createCodecService();
assertThat(codecService.codec("default"), instanceOf(PerFieldMapperCodec.class)); assertThat(codecService.codec("default"), instanceOf(PerFieldMapperCodec.class));
assertThat(codecService.codec("default"), instanceOf(Lucene94Codec.class)); assertThat(codecService.codec("default"), instanceOf(Lucene95Codec.class));
} }
public void testDefault() throws Exception { public void testDefault() throws Exception {
Codec codec = createCodecService().codec("default"); Codec codec = createCodecService().codec("default");
assertStoredFieldsCompressionEquals(Lucene94Codec.Mode.BEST_SPEED, codec); assertStoredFieldsCompressionEquals(Lucene95Codec.Mode.BEST_SPEED, codec);
} }
public void testBestCompression() throws Exception { public void testBestCompression() throws Exception {
Codec codec = createCodecService().codec("best_compression"); Codec codec = createCodecService().codec("best_compression");
assertStoredFieldsCompressionEquals(Lucene94Codec.Mode.BEST_COMPRESSION, codec); assertStoredFieldsCompressionEquals(Lucene95Codec.Mode.BEST_COMPRESSION, codec);
} }
// write some docs with it, inspect .si to see this was the used compression // write some docs with it, inspect .si to see this was the used compression
private void assertStoredFieldsCompressionEquals(Lucene94Codec.Mode expected, Codec actual) throws Exception { private void assertStoredFieldsCompressionEquals(Lucene95Codec.Mode expected, Codec actual) throws Exception {
Directory dir = newDirectory(); Directory dir = newDirectory();
IndexWriterConfig iwc = newIndexWriterConfig(null); IndexWriterConfig iwc = newIndexWriterConfig(null);
iwc.setCodec(actual); iwc.setCodec(actual);
@ -68,7 +68,7 @@ public class CodecTests extends ESTestCase {
SegmentReader sr = (SegmentReader) ir.leaves().get(0).reader(); SegmentReader sr = (SegmentReader) ir.leaves().get(0).reader();
String v = sr.getSegmentInfo().info.getAttribute(Lucene90StoredFieldsFormat.MODE_KEY); String v = sr.getSegmentInfo().info.getAttribute(Lucene90StoredFieldsFormat.MODE_KEY);
assertNotNull(v); assertNotNull(v);
assertEquals(expected, Lucene94Codec.Mode.valueOf(v)); assertEquals(expected, Lucene95Codec.Mode.valueOf(v));
ir.close(); ir.close();
dir.close(); dir.close();
} }

View file

@ -8,7 +8,7 @@
package org.elasticsearch.index.codec; package org.elasticsearch.index.codec;
import org.apache.lucene.codecs.lucene94.Lucene94Codec; import org.apache.lucene.codecs.lucene95.Lucene95Codec;
import org.elasticsearch.cluster.metadata.IndexMetadata; import org.elasticsearch.cluster.metadata.IndexMetadata;
import org.elasticsearch.common.compress.CompressedXContent; import org.elasticsearch.common.compress.CompressedXContent;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
@ -74,7 +74,7 @@ public class PerFieldMapperCodecTests extends ESTestCase {
"""; """;
mapperService.merge("type", new CompressedXContent(mapping), MapperService.MergeReason.MAPPING_UPDATE); mapperService.merge("type", new CompressedXContent(mapping), MapperService.MergeReason.MAPPING_UPDATE);
} }
return new PerFieldMapperCodec(Lucene94Codec.Mode.BEST_SPEED, mapperService, BigArrays.NON_RECYCLING_INSTANCE); return new PerFieldMapperCodec(Lucene95Codec.Mode.BEST_SPEED, mapperService, BigArrays.NON_RECYCLING_INSTANCE);
} }
} }

View file

@ -8,7 +8,7 @@
package org.elasticsearch.index.engine; package org.elasticsearch.index.engine;
import org.apache.lucene.codecs.PostingsFormat; import org.apache.lucene.codecs.PostingsFormat;
import org.apache.lucene.codecs.lucene94.Lucene94Codec; import org.apache.lucene.codecs.lucene95.Lucene95Codec;
import org.apache.lucene.document.Document; import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.IndexWriter;
@ -45,7 +45,7 @@ public class CompletionStatsCacheTests extends ESTestCase {
public void testCompletionStatsCache() throws IOException, InterruptedException { public void testCompletionStatsCache() throws IOException, InterruptedException {
final IndexWriterConfig indexWriterConfig = newIndexWriterConfig(); final IndexWriterConfig indexWriterConfig = newIndexWriterConfig();
final PostingsFormat postingsFormat = new Completion90PostingsFormat(); final PostingsFormat postingsFormat = new Completion90PostingsFormat();
indexWriterConfig.setCodec(new Lucene94Codec() { indexWriterConfig.setCodec(new Lucene95Codec() {
@Override @Override
public PostingsFormat getPostingsFormatForField(String field) { public PostingsFormat getPostingsFormatForField(String field) {
return postingsFormat; // all fields are suggest fields return postingsFormat; // all fields are suggest fields

View file

@ -16,9 +16,9 @@ import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig; import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.MultiReader; import org.apache.lucene.index.MultiReader;
import org.apache.lucene.index.SortedNumericDocValues; import org.apache.lucene.index.SortedNumericDocValues;
import org.apache.lucene.sandbox.search.IndexSortSortedNumericDocValuesRangeQuery;
import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.DocIdSetIterator;
import org.apache.lucene.search.IndexOrDocValuesQuery; import org.apache.lucene.search.IndexOrDocValuesQuery;
import org.apache.lucene.search.IndexSortSortedNumericDocValuesRangeQuery;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.apache.lucene.store.Directory; import org.apache.lucene.store.Directory;
import org.elasticsearch.Version; import org.elasticsearch.Version;

View file

@ -20,9 +20,9 @@ import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig; import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.sandbox.document.HalfFloatPoint; import org.apache.lucene.sandbox.document.HalfFloatPoint;
import org.apache.lucene.sandbox.search.IndexSortSortedNumericDocValuesRangeQuery;
import org.apache.lucene.search.IndexOrDocValuesQuery; import org.apache.lucene.search.IndexOrDocValuesQuery;
import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.IndexSortSortedNumericDocValuesRangeQuery;
import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.apache.lucene.search.Sort; import org.apache.lucene.search.Sort;

View file

@ -12,8 +12,9 @@ import com.carrotsearch.randomizedtesting.generators.RandomPicks;
import org.apache.lucene.codecs.Codec; import org.apache.lucene.codecs.Codec;
import org.apache.lucene.codecs.KnnVectorsFormat; import org.apache.lucene.codecs.KnnVectorsFormat;
import org.apache.lucene.codecs.lucene94.Lucene94HnswVectorsFormat; import org.apache.lucene.codecs.lucene95.Lucene95HnswVectorsFormat;
import org.apache.lucene.document.BinaryDocValuesField; import org.apache.lucene.document.BinaryDocValuesField;
import org.apache.lucene.document.KnnByteVectorField;
import org.apache.lucene.document.KnnVectorField; import org.apache.lucene.document.KnnVectorField;
import org.apache.lucene.index.IndexableField; import org.apache.lucene.index.IndexableField;
import org.apache.lucene.search.FieldExistsQuery; import org.apache.lucene.search.FieldExistsQuery;
@ -42,8 +43,8 @@ import java.nio.ByteBuffer;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import static org.apache.lucene.codecs.lucene94.Lucene94HnswVectorsFormat.DEFAULT_BEAM_WIDTH; import static org.apache.lucene.codecs.lucene95.Lucene95HnswVectorsFormat.DEFAULT_BEAM_WIDTH;
import static org.apache.lucene.codecs.lucene94.Lucene94HnswVectorsFormat.DEFAULT_MAX_CONN; import static org.apache.lucene.codecs.lucene95.Lucene95HnswVectorsFormat.DEFAULT_MAX_CONN;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.instanceOf;
@ -250,19 +251,19 @@ public class DenseVectorFieldMapperTests extends MapperTestCase {
) )
); );
float[] vector = { (byte) -1, (byte) 1, (byte) 127 }; byte[] vector = { (byte) -1, (byte) 1, (byte) 127 };
ParsedDocument doc1 = mapper.parse(source(b -> b.array("field", vector))); ParsedDocument doc1 = mapper.parse(source(b -> b.array("field", vector)));
IndexableField[] fields = doc1.rootDoc().getFields("field"); IndexableField[] fields = doc1.rootDoc().getFields("field");
assertEquals(1, fields.length); assertEquals(1, fields.length);
assertThat(fields[0], instanceOf(KnnVectorField.class)); assertThat(fields[0], instanceOf(KnnByteVectorField.class));
KnnVectorField vectorField = (KnnVectorField) fields[0]; KnnByteVectorField vectorField = (KnnByteVectorField) fields[0];
vectorField.binaryValue(); vectorField.vectorValue();
assertEquals( assertEquals(
"Parsed vector is not equal to original.", "Parsed vector is not equal to original.",
new BytesRef(new byte[] { (byte) -1, (byte) 1, (byte) 127 }), new BytesRef(new byte[] { (byte) -1, (byte) 1, (byte) 127 }),
vectorField.binaryValue() vectorField.vectorValue()
); );
assertEquals(similarity.function, vectorField.fieldType().vectorSimilarityFunction()); assertEquals(similarity.function, vectorField.fieldType().vectorSimilarityFunction());
} }
@ -332,9 +333,7 @@ public class DenseVectorFieldMapperTests extends MapperTestCase {
assertNotNull(e.getCause()); assertNotNull(e.getCause());
assertThat( assertThat(
e.getCause().getMessage(), e.getCause().getMessage(),
containsString( containsString("The [cosine] similarity does not support vectors with zero magnitude. Preview of invalid vector: [0, 0, 0]")
"The [cosine] similarity does not support vectors with zero magnitude. Preview of invalid vector: [-0.0, 0.0, 0.0]"
)
); );
} }
@ -544,7 +543,13 @@ public class DenseVectorFieldMapperTests extends MapperTestCase {
); );
assertThat( assertThat(
e.getCause().getMessage(), e.getCause().getMessage(),
containsString("element_type [byte] vectors only support integers between [-128, 127] but found [128.0] at dim [0];") containsString("element_type [byte] vectors only support integers between [-128, 127] but found [128] at dim [0];")
);
e = expectThrows(MapperParsingException.class, () -> mapper.parse(source(b -> b.array("field", new float[] { 18.2f, 0, 0 }))));
assertThat(
e.getCause().getMessage(),
containsString("element_type [byte] vectors only support non-decimal values but found decimal value [18.2] at dim [0];")
); );
e = expectThrows( e = expectThrows(
@ -553,7 +558,7 @@ public class DenseVectorFieldMapperTests extends MapperTestCase {
); );
assertThat( assertThat(
e.getCause().getMessage(), e.getCause().getMessage(),
containsString("element_type [byte] vectors only support integers between [-128, 127] but found [-129.0] at dim [2];") containsString("element_type [byte] vectors only support integers between [-128, 127] but found [-129] at dim [2];")
); );
} }
@ -693,8 +698,8 @@ public class DenseVectorFieldMapperTests extends MapperTestCase {
Codec codec = codecService.codec("default"); Codec codec = codecService.codec("default");
assertThat(codec, instanceOf(PerFieldMapperCodec.class)); assertThat(codec, instanceOf(PerFieldMapperCodec.class));
KnnVectorsFormat knnVectorsFormat = ((PerFieldMapperCodec) codec).getKnnVectorsFormatForField("field"); KnnVectorsFormat knnVectorsFormat = ((PerFieldMapperCodec) codec).getKnnVectorsFormatForField("field");
assertThat(knnVectorsFormat, instanceOf(Lucene94HnswVectorsFormat.class)); assertThat(knnVectorsFormat, instanceOf(Lucene95HnswVectorsFormat.class));
String expectedString = "Lucene94HnswVectorsFormat(name=Lucene94HnswVectorsFormat, maxConn=" String expectedString = "Lucene95HnswVectorsFormat(name=Lucene95HnswVectorsFormat, maxConn="
+ m + m
+ ", beamWidth=" + ", beamWidth="
+ efConstruction + efConstruction
@ -725,14 +730,12 @@ public class DenseVectorFieldMapperTests extends MapperTestCase {
@Override @Override
public SyntheticSourceExample example(int maxValues) throws IOException { public SyntheticSourceExample example(int maxValues) throws IOException {
List<Float> value = randomList(dims, dims, this::randomValue); Object value = elementType == ElementType.BYTE
? randomList(dims, dims, ESTestCase::randomByte)
: randomList(dims, dims, ESTestCase::randomFloat);
return new SyntheticSourceExample(value, value, this::mapping); return new SyntheticSourceExample(value, value, this::mapping);
} }
private float randomValue() {
return elementType == ElementType.BYTE ? ESTestCase.randomByte() : ESTestCase.randomFloat();
}
private void mapping(XContentBuilder b) throws IOException { private void mapping(XContentBuilder b) throws IOException {
b.field("type", "dense_vector"); b.field("type", "dense_vector");
b.field("dims", dims); b.field("dims", dims);
@ -753,7 +756,7 @@ public class DenseVectorFieldMapperTests extends MapperTestCase {
} }
@Override @Override
public List<SyntheticSourceInvalidExample> invalidExample() throws IOException { public List<SyntheticSourceInvalidExample> invalidExample() {
return List.of(); return List.of();
} }
} }

View file

@ -8,6 +8,7 @@
package org.elasticsearch.index.mapper.vectors; package org.elasticsearch.index.mapper.vectors;
import org.apache.lucene.util.BytesRef;
import org.elasticsearch.Version; import org.elasticsearch.Version;
import org.elasticsearch.index.fielddata.FieldDataContext; import org.elasticsearch.index.fielddata.FieldDataContext;
import org.elasticsearch.index.mapper.FieldTypeTestCase; import org.elasticsearch.index.mapper.FieldTypeTestCase;
@ -174,5 +175,8 @@ public class DenseVectorFieldTypeTests extends FieldTypeTestCase {
); );
e = expectThrows(IllegalArgumentException.class, () -> cosineField.createKnnQuery(new float[] { 0.0f, 0.0f, 0.0f }, 10, null)); e = expectThrows(IllegalArgumentException.class, () -> cosineField.createKnnQuery(new float[] { 0.0f, 0.0f, 0.0f }, 10, null));
assertThat(e.getMessage(), containsString("The [cosine] similarity does not support vectors with zero magnitude.")); assertThat(e.getMessage(), containsString("The [cosine] similarity does not support vectors with zero magnitude."));
e = expectThrows(IllegalArgumentException.class, () -> cosineField.createKnnQuery(new BytesRef(new byte[] { 0, 0, 0 }), 10, null));
assertThat(e.getMessage(), containsString("The [cosine] similarity does not support vectors with zero magnitude."));
} }
} }

View file

@ -8,9 +8,9 @@
package org.elasticsearch.index.mapper.vectors; package org.elasticsearch.index.mapper.vectors;
import org.apache.lucene.index.ByteVectorValues;
import org.apache.lucene.index.VectorValues; import org.apache.lucene.index.VectorValues;
import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.VectorUtil;
import org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper.ElementType; import org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper.ElementType;
import org.elasticsearch.script.field.vectors.ByteKnnDenseVectorDocValuesField; import org.elasticsearch.script.field.vectors.ByteKnnDenseVectorDocValuesField;
import org.elasticsearch.script.field.vectors.DenseVector; import org.elasticsearch.script.field.vectors.DenseVector;
@ -30,12 +30,7 @@ public class KnnDenseVectorScriptDocValuesTests extends ESTestCase {
float[][] vectors = { { 1, 1, 1 }, { 1, 1, 2 }, { 1, 1, 3 } }; float[][] vectors = { { 1, 1, 1 }, { 1, 1, 2 }, { 1, 1, 3 } };
float[] expectedMagnitudes = { 1.7320f, 2.4495f, 3.3166f }; float[] expectedMagnitudes = { 1.7320f, 2.4495f, 3.3166f };
DenseVectorDocValuesField field = new KnnDenseVectorDocValuesField( DenseVectorDocValuesField field = new KnnDenseVectorDocValuesField(wrap(vectors), "test", dims);
wrap(vectors, ElementType.FLOAT),
"test",
ElementType.FLOAT,
dims
);
DenseVectorScriptDocValues scriptDocValues = field.toScriptDocValues(); DenseVectorScriptDocValues scriptDocValues = field.toScriptDocValues();
for (int i = 0; i < vectors.length; i++) { for (int i = 0; i < vectors.length; i++) {
field.setNextDocId(i); field.setNextDocId(i);
@ -51,12 +46,7 @@ public class KnnDenseVectorScriptDocValuesTests extends ESTestCase {
float[][] vectors = { { 1, 1, 1 }, { 1, 1, 2 }, { 1, 1, 3 } }; float[][] vectors = { { 1, 1, 1 }, { 1, 1, 2 }, { 1, 1, 3 } };
float[] expectedMagnitudes = { 1.7320f, 2.4495f, 3.3166f }; float[] expectedMagnitudes = { 1.7320f, 2.4495f, 3.3166f };
DenseVectorDocValuesField field = new ByteKnnDenseVectorDocValuesField( DenseVectorDocValuesField field = new ByteKnnDenseVectorDocValuesField(wrapBytes(vectors), "test", dims);
wrap(vectors, ElementType.BYTE),
"test",
ElementType.BYTE,
dims
);
DenseVectorScriptDocValues scriptDocValues = field.toScriptDocValues(); DenseVectorScriptDocValues scriptDocValues = field.toScriptDocValues();
for (int i = 0; i < vectors.length; i++) { for (int i = 0; i < vectors.length; i++) {
field.setNextDocId(i); field.setNextDocId(i);
@ -70,12 +60,7 @@ public class KnnDenseVectorScriptDocValuesTests extends ESTestCase {
public void testFloatMetadataAndIterator() throws IOException { public void testFloatMetadataAndIterator() throws IOException {
int dims = 3; int dims = 3;
float[][] vectors = fill(new float[randomIntBetween(1, 5)][dims], ElementType.FLOAT); float[][] vectors = fill(new float[randomIntBetween(1, 5)][dims], ElementType.FLOAT);
DenseVectorDocValuesField field = new KnnDenseVectorDocValuesField( DenseVectorDocValuesField field = new KnnDenseVectorDocValuesField(wrap(vectors), "test", dims);
wrap(vectors, ElementType.FLOAT),
"test",
ElementType.FLOAT,
dims
);
for (int i = 0; i < vectors.length; i++) { for (int i = 0; i < vectors.length; i++) {
field.setNextDocId(i); field.setNextDocId(i);
DenseVector dv = field.get(); DenseVector dv = field.get();
@ -94,12 +79,7 @@ public class KnnDenseVectorScriptDocValuesTests extends ESTestCase {
public void testByteMetadataAndIterator() throws IOException { public void testByteMetadataAndIterator() throws IOException {
int dims = 3; int dims = 3;
float[][] vectors = fill(new float[randomIntBetween(1, 5)][dims], ElementType.BYTE); float[][] vectors = fill(new float[randomIntBetween(1, 5)][dims], ElementType.BYTE);
DenseVectorDocValuesField field = new ByteKnnDenseVectorDocValuesField( DenseVectorDocValuesField field = new ByteKnnDenseVectorDocValuesField(wrapBytes(vectors), "test", dims);
wrap(vectors, ElementType.BYTE),
"test",
ElementType.BYTE,
dims
);
for (int i = 0; i < vectors.length; i++) { for (int i = 0; i < vectors.length; i++) {
field.setNextDocId(i); field.setNextDocId(i);
DenseVector dv = field.get(); DenseVector dv = field.get();
@ -127,12 +107,7 @@ public class KnnDenseVectorScriptDocValuesTests extends ESTestCase {
public void testFloatMissingValues() throws IOException { public void testFloatMissingValues() throws IOException {
int dims = 3; int dims = 3;
float[][] vectors = { { 1, 1, 1 }, { 1, 1, 2 }, { 1, 1, 3 } }; float[][] vectors = { { 1, 1, 1 }, { 1, 1, 2 }, { 1, 1, 3 } };
DenseVectorDocValuesField field = new KnnDenseVectorDocValuesField( DenseVectorDocValuesField field = new KnnDenseVectorDocValuesField(wrap(vectors), "test", dims);
wrap(vectors, ElementType.FLOAT),
"test",
ElementType.FLOAT,
dims
);
DenseVectorScriptDocValues scriptDocValues = field.toScriptDocValues(); DenseVectorScriptDocValues scriptDocValues = field.toScriptDocValues();
field.setNextDocId(3); field.setNextDocId(3);
@ -146,12 +121,7 @@ public class KnnDenseVectorScriptDocValuesTests extends ESTestCase {
public void testByteMissingValues() throws IOException { public void testByteMissingValues() throws IOException {
int dims = 3; int dims = 3;
float[][] vectors = { { 1, 1, 1 }, { 1, 1, 2 }, { 1, 1, 3 } }; float[][] vectors = { { 1, 1, 1 }, { 1, 1, 2 }, { 1, 1, 3 } };
DenseVectorDocValuesField field = new ByteKnnDenseVectorDocValuesField( DenseVectorDocValuesField field = new ByteKnnDenseVectorDocValuesField(wrapBytes(vectors), "test", dims);
wrap(vectors, ElementType.BYTE),
"test",
ElementType.BYTE,
dims
);
DenseVectorScriptDocValues scriptDocValues = field.toScriptDocValues(); DenseVectorScriptDocValues scriptDocValues = field.toScriptDocValues();
field.setNextDocId(3); field.setNextDocId(3);
@ -165,12 +135,7 @@ public class KnnDenseVectorScriptDocValuesTests extends ESTestCase {
public void testFloatGetFunctionIsNotAccessible() throws IOException { public void testFloatGetFunctionIsNotAccessible() throws IOException {
int dims = 3; int dims = 3;
float[][] vectors = { { 1, 1, 1 }, { 1, 1, 2 }, { 1, 1, 3 } }; float[][] vectors = { { 1, 1, 1 }, { 1, 1, 2 }, { 1, 1, 3 } };
DenseVectorDocValuesField field = new KnnDenseVectorDocValuesField( DenseVectorDocValuesField field = new KnnDenseVectorDocValuesField(wrap(vectors), "test", dims);
wrap(vectors, ElementType.FLOAT),
"test",
ElementType.FLOAT,
dims
);
DenseVectorScriptDocValues scriptDocValues = field.toScriptDocValues(); DenseVectorScriptDocValues scriptDocValues = field.toScriptDocValues();
field.setNextDocId(0); field.setNextDocId(0);
@ -186,12 +151,7 @@ public class KnnDenseVectorScriptDocValuesTests extends ESTestCase {
public void testByteGetFunctionIsNotAccessible() throws IOException { public void testByteGetFunctionIsNotAccessible() throws IOException {
int dims = 3; int dims = 3;
float[][] vectors = { { 1, 1, 1 }, { 1, 1, 2 }, { 1, 1, 3 } }; float[][] vectors = { { 1, 1, 1 }, { 1, 1, 2 }, { 1, 1, 3 } };
DenseVectorDocValuesField field = new ByteKnnDenseVectorDocValuesField( DenseVectorDocValuesField field = new ByteKnnDenseVectorDocValuesField(wrapBytes(vectors), "test", dims);
wrap(vectors, ElementType.BYTE),
"test",
ElementType.BYTE,
dims
);
DenseVectorScriptDocValues scriptDocValues = field.toScriptDocValues(); DenseVectorScriptDocValues scriptDocValues = field.toScriptDocValues();
field.setNextDocId(0); field.setNextDocId(0);
@ -206,7 +166,7 @@ public class KnnDenseVectorScriptDocValuesTests extends ESTestCase {
public void testFloatMissingVectorValues() throws IOException { public void testFloatMissingVectorValues() throws IOException {
int dims = 7; int dims = 7;
DenseVectorDocValuesField emptyKnn = new KnnDenseVectorDocValuesField(null, "test", ElementType.FLOAT, dims); DenseVectorDocValuesField emptyKnn = new KnnDenseVectorDocValuesField(null, "test", dims);
emptyKnn.setNextDocId(0); emptyKnn.setNextDocId(0);
assertEquals(0, emptyKnn.toScriptDocValues().size()); assertEquals(0, emptyKnn.toScriptDocValues().size());
@ -220,7 +180,7 @@ public class KnnDenseVectorScriptDocValuesTests extends ESTestCase {
public void testByteMissingVectorValues() throws IOException { public void testByteMissingVectorValues() throws IOException {
int dims = 7; int dims = 7;
DenseVectorDocValuesField emptyKnn = new ByteKnnDenseVectorDocValuesField(null, "test", ElementType.BYTE, dims); DenseVectorDocValuesField emptyKnn = new ByteKnnDenseVectorDocValuesField(null, "test", dims);
emptyKnn.setNextDocId(0); emptyKnn.setNextDocId(0);
assertEquals(0, emptyKnn.toScriptDocValues().size()); assertEquals(0, emptyKnn.toScriptDocValues().size());
@ -232,7 +192,50 @@ public class KnnDenseVectorScriptDocValuesTests extends ESTestCase {
assertEquals("Cannot iterate over single valued dense_vector field, use get() instead", e.getMessage()); assertEquals("Cannot iterate over single valued dense_vector field, use get() instead", e.getMessage());
} }
public static VectorValues wrap(float[][] vectors, ElementType elementType) { public static ByteVectorValues wrapBytes(float[][] vectors) {
return new ByteVectorValues() {
int index = 0;
byte[] byteVector = new byte[vectors[0].length];
@Override
public int dimension() {
return 0;
}
@Override
public int size() {
return vectors.length;
}
@Override
public BytesRef vectorValue() {
for (int i = 0; i < byteVector.length; i++) {
byteVector[i] = (byte) vectors[index][i];
}
return new BytesRef(byteVector);
}
@Override
public int docID() {
return index;
}
@Override
public int nextDoc() {
throw new UnsupportedOperationException();
}
@Override
public int advance(int target) {
if (target >= size()) {
return NO_MORE_DOCS;
}
return index = target;
}
};
}
public static VectorValues wrap(float[][] vectors) {
return new VectorValues() { return new VectorValues() {
int index = 0; int index = 0;
@ -253,17 +256,11 @@ public class KnnDenseVectorScriptDocValuesTests extends ESTestCase {
@Override @Override
public BytesRef binaryValue() { public BytesRef binaryValue() {
if (elementType == ElementType.FLOAT) { ByteBuffer byteBuffer = ByteBuffer.allocate(ElementType.FLOAT.elementBytes * vectors[index].length);
ByteBuffer byteBuffer = ByteBuffer.allocate(elementType.elementBytes * vectors[index].length); for (float value : vectors[index]) {
for (float value : vectors[index]) { ElementType.FLOAT.writeValue(byteBuffer, value);
elementType.writeValue(byteBuffer, value);
}
return new BytesRef(byteBuffer.array());
} else if (elementType == ElementType.BYTE) {
return VectorUtil.toBytesRef(vectors[index]);
} else {
throw new IllegalStateException("unknown element_type [" + elementType + "]");
} }
return new BytesRef(byteBuffer.array());
} }
@Override @Override
@ -283,11 +280,6 @@ public class KnnDenseVectorScriptDocValuesTests extends ESTestCase {
} }
return index = target; return index = target;
} }
@Override
public long cost() {
return size();
}
}; };
} }
} }

View file

@ -55,12 +55,7 @@ public class VectorScoreScriptUtilsTests extends ESTestCase {
dims, dims,
Version.CURRENT Version.CURRENT
), ),
new KnnDenseVectorDocValuesField( new KnnDenseVectorDocValuesField(KnnDenseVectorScriptDocValuesTests.wrap(new float[][] { docVector }), "test", dims)
KnnDenseVectorScriptDocValuesTests.wrap(new float[][] { docVector }, ElementType.FLOAT),
"test",
ElementType.FLOAT,
dims
)
); );
for (DenseVectorDocValuesField field : fields) { for (DenseVectorDocValuesField field : fields) {
field.setNextDocId(0); field.setNextDocId(0);
@ -140,12 +135,7 @@ public class VectorScoreScriptUtilsTests extends ESTestCase {
ElementType.BYTE, ElementType.BYTE,
dims dims
), ),
new ByteKnnDenseVectorDocValuesField( new ByteKnnDenseVectorDocValuesField(KnnDenseVectorScriptDocValuesTests.wrapBytes(new float[][] { docVector }), "test", dims)
KnnDenseVectorScriptDocValuesTests.wrap(new float[][] { docVector }, ElementType.BYTE),
"test",
ElementType.BYTE,
dims
)
); );
for (DenseVectorDocValuesField field : fields) { for (DenseVectorDocValuesField field : fields) {
field.setNextDocId(0); field.setNextDocId(0);
@ -233,24 +223,14 @@ public class VectorScoreScriptUtilsTests extends ESTestCase {
dims, dims,
Version.CURRENT Version.CURRENT
), ),
new KnnDenseVectorDocValuesField( new KnnDenseVectorDocValuesField(KnnDenseVectorScriptDocValuesTests.wrap(new float[][] { docVector }), "field2", dims),
KnnDenseVectorScriptDocValuesTests.wrap(new float[][] { docVector }, ElementType.FLOAT),
"field2",
ElementType.FLOAT,
dims
),
new ByteBinaryDenseVectorDocValuesField( new ByteBinaryDenseVectorDocValuesField(
BinaryDenseVectorScriptDocValuesTests.wrap(new float[][] { docVector }, ElementType.BYTE, Version.CURRENT), BinaryDenseVectorScriptDocValuesTests.wrap(new float[][] { docVector }, ElementType.BYTE, Version.CURRENT),
"field3", "field3",
ElementType.BYTE, ElementType.BYTE,
dims dims
), ),
new ByteKnnDenseVectorDocValuesField( new ByteKnnDenseVectorDocValuesField(KnnDenseVectorScriptDocValuesTests.wrapBytes(new float[][] { docVector }), "field4", dims)
KnnDenseVectorScriptDocValuesTests.wrap(new float[][] { docVector }, ElementType.BYTE),
"field4",
ElementType.BYTE,
dims
)
); );
for (DenseVectorDocValuesField field : fields) { for (DenseVectorDocValuesField field : fields) {
field.setNextDocId(0); field.setNextDocId(0);
@ -388,12 +368,7 @@ public class VectorScoreScriptUtilsTests extends ESTestCase {
ElementType.BYTE, ElementType.BYTE,
dims dims
), ),
new ByteKnnDenseVectorDocValuesField( new ByteKnnDenseVectorDocValuesField(KnnDenseVectorScriptDocValuesTests.wrapBytes(new float[][] { docVector }), "test", dims)
KnnDenseVectorScriptDocValuesTests.wrap(new float[][] { docVector }, ElementType.BYTE),
"test",
ElementType.BYTE,
dims
)
); );
for (DenseVectorDocValuesField field : fields) { for (DenseVectorDocValuesField field : fields) {

View file

@ -0,0 +1,245 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
package org.elasticsearch.search.vectors;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.KnnByteVectorQuery;
import org.apache.lucene.search.KnnVectorQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.util.BytesRef;
import org.elasticsearch.Version;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.compress.CompressedXContent;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.io.stream.NamedWriteableAwareStreamInput;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.core.Tuple;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper;
import org.elasticsearch.index.query.MatchNoneQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.SearchExecutionContext;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.test.AbstractBuilderTestCase;
import org.elasticsearch.test.AbstractQueryTestCase;
import org.elasticsearch.test.VersionUtils;
import org.elasticsearch.xcontent.XContentBuilder;
import org.elasticsearch.xcontent.XContentFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.instanceOf;
abstract class AbstractKnnVectorQueryBuilderTestCase extends AbstractQueryTestCase<KnnVectorQueryBuilder> {
private static final String VECTOR_FIELD = "vector";
private static final String VECTOR_ALIAS_FIELD = "vector_alias";
private static final int VECTOR_DIMENSION = 3;
abstract DenseVectorFieldMapper.ElementType elementType();
@Override
protected void initializeAdditionalMappings(MapperService mapperService) throws IOException {
XContentBuilder builder = XContentFactory.jsonBuilder()
.startObject()
.startObject("properties")
.startObject(VECTOR_FIELD)
.field("type", "dense_vector")
.field("dims", VECTOR_DIMENSION)
.field("index", true)
.field("similarity", "l2_norm")
.field("element_type", elementType())
.endObject()
.startObject(VECTOR_ALIAS_FIELD)
.field("type", "alias")
.field("path", VECTOR_FIELD)
.endObject()
.endObject()
.endObject();
mapperService.merge(
MapperService.SINGLE_MAPPING_NAME,
new CompressedXContent(Strings.toString(builder)),
MapperService.MergeReason.MAPPING_UPDATE
);
}
@Override
protected KnnVectorQueryBuilder doCreateTestQueryBuilder() {
String fieldName = randomBoolean() ? VECTOR_FIELD : VECTOR_ALIAS_FIELD;
byte[] byteVector = new byte[VECTOR_DIMENSION];
float[] vector = new float[VECTOR_DIMENSION];
for (int i = 0; i < vector.length; i++) {
vector[i] = randomFloat();
byteVector[i] = randomByte();
}
int numCands = randomIntBetween(1, 1000);
KnnVectorQueryBuilder queryBuilder = switch (elementType()) {
case BYTE -> new KnnVectorQueryBuilder(fieldName, byteVector, numCands);
case FLOAT -> new KnnVectorQueryBuilder(fieldName, vector, numCands);
};
if (randomBoolean()) {
List<QueryBuilder> filters = new ArrayList<>();
int numFilters = randomIntBetween(1, 5);
for (int i = 0; i < numFilters; i++) {
String filterFieldName = randomBoolean() ? KEYWORD_FIELD_NAME : TEXT_FIELD_NAME;
filters.add(QueryBuilders.termQuery(filterFieldName, randomAlphaOfLength(10)));
}
queryBuilder.addFilterQueries(filters);
}
return queryBuilder;
}
@Override
protected void doAssertLuceneQuery(KnnVectorQueryBuilder queryBuilder, Query query, SearchExecutionContext context) throws IOException {
switch (elementType()) {
case FLOAT -> assertTrue(query instanceof KnnVectorQuery);
case BYTE -> assertTrue(query instanceof KnnByteVectorQuery);
}
BooleanQuery.Builder builder = new BooleanQuery.Builder();
for (QueryBuilder qb : queryBuilder.filterQueries()) {
builder.add(qb.toQuery(context), BooleanClause.Occur.FILTER);
}
BooleanQuery booleanQuery = builder.build();
Query filterQuery = booleanQuery.clauses().isEmpty() ? null : booleanQuery;
// The field should always be resolved to the concrete field
Query knnVectorQueryBuilt = switch (elementType()) {
case BYTE -> new KnnByteVectorQuery(
VECTOR_FIELD,
new BytesRef(queryBuilder.getByteQueryVector()),
queryBuilder.numCands(),
filterQuery
);
case FLOAT -> new KnnVectorQuery(VECTOR_FIELD, queryBuilder.queryVector(), queryBuilder.numCands(), filterQuery);
};
assertEquals(query, knnVectorQueryBuilt);
}
public void testWrongDimension() {
SearchExecutionContext context = createSearchExecutionContext();
KnnVectorQueryBuilder query = new KnnVectorQueryBuilder(VECTOR_FIELD, new float[] { 1.0f, 2.0f }, 10);
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> query.doToQuery(context));
assertThat(e.getMessage(), containsString("the query vector has a different dimension [2] than the index vectors [3]"));
}
public void testNonexistentField() {
SearchExecutionContext context = createSearchExecutionContext();
KnnVectorQueryBuilder query = new KnnVectorQueryBuilder("nonexistent", new float[] { 1.0f, 1.0f, 1.0f }, 10);
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> query.doToQuery(context));
assertThat(e.getMessage(), containsString("field [nonexistent] does not exist in the mapping"));
}
public void testWrongFieldType() {
SearchExecutionContext context = createSearchExecutionContext();
KnnVectorQueryBuilder query = new KnnVectorQueryBuilder(
AbstractBuilderTestCase.KEYWORD_FIELD_NAME,
new float[] { 1.0f, 1.0f, 1.0f },
10
);
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> query.doToQuery(context));
assertThat(e.getMessage(), containsString("[knn] queries are only supported on [dense_vector] fields"));
}
@Override
public void testValidOutput() {
KnnVectorQueryBuilder query = new KnnVectorQueryBuilder(VECTOR_FIELD, new float[] { 1.0f, 2.0f, 3.0f }, 10);
String expected = """
{
"knn" : {
"field" : "vector",
"vector" : [
1.0,
2.0,
3.0
],
"num_candidates" : 10
}
}""";
assertEquals(expected, query.toString());
}
@Override
public void testMustRewrite() throws IOException {
SearchExecutionContext context = createSearchExecutionContext();
context.setAllowUnmappedFields(true);
TermQueryBuilder termQuery = new TermQueryBuilder("unmapped_field", 42);
KnnVectorQueryBuilder query = new KnnVectorQueryBuilder(VECTOR_FIELD, new float[] { 1.0f, 2.0f, 3.0f }, VECTOR_DIMENSION);
query.addFilterQuery(termQuery);
IllegalStateException e = expectThrows(IllegalStateException.class, () -> query.toQuery(context));
assertEquals("Rewrite first", e.getMessage());
QueryBuilder rewrittenQuery = query.rewrite(context);
assertThat(rewrittenQuery, instanceOf(MatchNoneQueryBuilder.class));
}
public void testBWCVersionSerialization() throws IOException {
float[] bwcFloat = new float[VECTOR_DIMENSION];
KnnVectorQueryBuilder query = createTestQueryBuilder();
if (query.queryVector() != null) {
bwcFloat = query.queryVector();
} else {
for (int i = 0; i < query.getByteQueryVector().length; i++) {
bwcFloat[i] = query.getByteQueryVector()[i];
}
}
KnnVectorQueryBuilder queryWithNoFilters = new KnnVectorQueryBuilder(query.getFieldName(), bwcFloat, query.numCands()).queryName(
query.queryName()
).boost(query.boost());
KnnVectorQueryBuilder queryNoByteQuery = new KnnVectorQueryBuilder(query.getFieldName(), bwcFloat, query.numCands()).queryName(
query.queryName()
).boost(query.boost()).addFilterQueries(query.filterQueries());
Version newVersion = VersionUtils.randomVersionBetween(random(), Version.V_8_7_0, Version.CURRENT);
Version beforeByteQueryVersion = VersionUtils.randomVersionBetween(random(), Version.V_8_2_0, Version.V_8_6_0);
Version beforeFilterVersion = VersionUtils.randomVersionBetween(random(), Version.V_8_0_0, Version.V_8_1_0);
assertSerialization(query, newVersion);
assertSerialization(queryNoByteQuery, beforeByteQueryVersion);
assertSerialization(queryWithNoFilters, beforeFilterVersion);
for (var tuple : List.of(
Tuple.tuple(beforeByteQueryVersion, queryNoByteQuery),
Tuple.tuple(beforeFilterVersion, queryWithNoFilters)
)) {
try (BytesStreamOutput output = new BytesStreamOutput()) {
output.setVersion(tuple.v1());
output.writeNamedWriteable(query);
try (StreamInput in = new NamedWriteableAwareStreamInput(output.bytes().streamInput(), namedWriteableRegistry())) {
in.setVersion(tuple.v1());
KnnVectorQueryBuilder deserializedQuery = (KnnVectorQueryBuilder) in.readNamedWriteable(QueryBuilder.class);
assertEquals(tuple.v2(), deserializedQuery);
assertEquals(tuple.v2().hashCode(), deserializedQuery.hashCode());
}
}
}
}
@Override
public void testUnknownObjectException() {
assumeTrue("Test isn't relevant, since query is never parsed from xContent", false);
}
@Override
public void testFromXContent() {
assumeTrue("Test isn't relevant, since query is never parsed from xContent", false);
}
@Override
public void testUnknownField() {
assumeTrue("Test isn't relevant, since query is never parsed from xContent", false);
}
}

View file

@ -0,0 +1,18 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
package org.elasticsearch.search.vectors;
import org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper;
public class KnnByteVectorQueryBuilderTests extends AbstractKnnVectorQueryBuilderTestCase {
@Override
DenseVectorFieldMapper.ElementType elementType() {
return DenseVectorFieldMapper.ElementType.BYTE;
}
}

View file

@ -8,196 +8,11 @@
package org.elasticsearch.search.vectors; package org.elasticsearch.search.vectors;
import org.apache.lucene.search.BooleanClause; import org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.KnnVectorQuery;
import org.apache.lucene.search.Query;
import org.elasticsearch.Version;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.compress.CompressedXContent;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.io.stream.NamedWriteableAwareStreamInput;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.query.MatchNoneQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.SearchExecutionContext;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.test.AbstractBuilderTestCase;
import org.elasticsearch.test.AbstractQueryTestCase;
import org.elasticsearch.test.VersionUtils;
import org.elasticsearch.xcontent.XContentBuilder;
import org.elasticsearch.xcontent.XContentFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.instanceOf;
public class KnnVectorQueryBuilderTests extends AbstractQueryTestCase<KnnVectorQueryBuilder> {
private static final String VECTOR_FIELD = "vector";
private static final String VECTOR_ALIAS_FIELD = "vector_alias";
private static final int VECTOR_DIMENSION = 3;
public class KnnVectorQueryBuilderTests extends AbstractKnnVectorQueryBuilderTestCase {
@Override @Override
protected void initializeAdditionalMappings(MapperService mapperService) throws IOException { DenseVectorFieldMapper.ElementType elementType() {
XContentBuilder builder = XContentFactory.jsonBuilder() return DenseVectorFieldMapper.ElementType.FLOAT;
.startObject()
.startObject("properties")
.startObject(VECTOR_FIELD)
.field("type", "dense_vector")
.field("dims", VECTOR_DIMENSION)
.field("index", true)
.field("similarity", "l2_norm")
.endObject()
.startObject(VECTOR_ALIAS_FIELD)
.field("type", "alias")
.field("path", VECTOR_FIELD)
.endObject()
.endObject()
.endObject();
mapperService.merge(
MapperService.SINGLE_MAPPING_NAME,
new CompressedXContent(Strings.toString(builder)),
MapperService.MergeReason.MAPPING_UPDATE
);
}
@Override
protected KnnVectorQueryBuilder doCreateTestQueryBuilder() {
String fieldName = randomBoolean() ? VECTOR_FIELD : VECTOR_ALIAS_FIELD;
float[] vector = new float[VECTOR_DIMENSION];
for (int i = 0; i < vector.length; i++) {
vector[i] = randomFloat();
}
int numCands = randomIntBetween(1, 1000);
KnnVectorQueryBuilder queryBuilder = new KnnVectorQueryBuilder(fieldName, vector, numCands);
if (randomBoolean()) {
List<QueryBuilder> filters = new ArrayList<>();
int numFilters = randomIntBetween(1, 5);
for (int i = 0; i < numFilters; i++) {
String filterFieldName = randomBoolean() ? KEYWORD_FIELD_NAME : TEXT_FIELD_NAME;
filters.add(QueryBuilders.termQuery(filterFieldName, randomAlphaOfLength(10)));
}
queryBuilder.addFilterQueries(filters);
}
return queryBuilder;
}
@Override
protected void doAssertLuceneQuery(KnnVectorQueryBuilder queryBuilder, Query query, SearchExecutionContext context) throws IOException {
assertTrue(query instanceof KnnVectorQuery);
KnnVectorQuery knnVectorQuery = (KnnVectorQuery) query;
BooleanQuery.Builder builder = new BooleanQuery.Builder();
for (QueryBuilder qb : queryBuilder.filterQueries()) {
builder.add(qb.toQuery(context), BooleanClause.Occur.FILTER);
}
BooleanQuery booleanQuery = builder.build();
Query filterQuery = booleanQuery.clauses().isEmpty() ? null : booleanQuery;
// The field should always be resolved to the concrete field
Query knnVectorQueryBuilt = new KnnVectorQuery(VECTOR_FIELD, queryBuilder.queryVector(), queryBuilder.numCands(), filterQuery);
assertEquals(knnVectorQuery, knnVectorQueryBuilt);
}
public void testWrongDimension() {
SearchExecutionContext context = createSearchExecutionContext();
KnnVectorQueryBuilder query = new KnnVectorQueryBuilder(VECTOR_FIELD, new float[] { 1.0f, 2.0f }, 10);
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> query.doToQuery(context));
assertThat(e.getMessage(), containsString("the query vector has a different dimension [2] than the index vectors [3]"));
}
public void testNonexistentField() {
SearchExecutionContext context = createSearchExecutionContext();
KnnVectorQueryBuilder query = new KnnVectorQueryBuilder("nonexistent", new float[] { 1.0f, 1.0f, 1.0f }, 10);
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> query.doToQuery(context));
assertThat(e.getMessage(), containsString("field [nonexistent] does not exist in the mapping"));
}
public void testWrongFieldType() {
SearchExecutionContext context = createSearchExecutionContext();
KnnVectorQueryBuilder query = new KnnVectorQueryBuilder(
AbstractBuilderTestCase.KEYWORD_FIELD_NAME,
new float[] { 1.0f, 1.0f, 1.0f },
10
);
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> query.doToQuery(context));
assertThat(e.getMessage(), containsString("[knn] queries are only supported on [dense_vector] fields"));
}
@Override
public void testValidOutput() {
KnnVectorQueryBuilder query = new KnnVectorQueryBuilder(VECTOR_FIELD, new float[] { 1.0f, 2.0f, 3.0f }, 10);
String expected = """
{
"knn" : {
"field" : "vector",
"vector" : [
1.0,
2.0,
3.0
],
"num_candidates" : 10
}
}""";
assertEquals(expected, query.toString());
}
@Override
public void testMustRewrite() throws IOException {
SearchExecutionContext context = createSearchExecutionContext();
context.setAllowUnmappedFields(true);
TermQueryBuilder termQuery = new TermQueryBuilder("unmapped_field", 42);
KnnVectorQueryBuilder query = new KnnVectorQueryBuilder(VECTOR_FIELD, new float[] { 1.0f, 2.0f, 3.0f }, VECTOR_DIMENSION);
query.addFilterQuery(termQuery);
IllegalStateException e = expectThrows(IllegalStateException.class, () -> query.toQuery(context));
assertEquals("Rewrite first", e.getMessage());
QueryBuilder rewrittenQuery = query.rewrite(context);
assertThat(rewrittenQuery, instanceOf(MatchNoneQueryBuilder.class));
}
public void testOldVersionSerialization() throws IOException {
KnnVectorQueryBuilder query = createTestQueryBuilder();
KnnVectorQueryBuilder queryWithNoFilters = new KnnVectorQueryBuilder(query.getFieldName(), query.queryVector(), query.numCands());
queryWithNoFilters.queryName(query.queryName()).boost(query.boost());
Version newVersion = VersionUtils.randomVersionBetween(random(), Version.V_8_2_0, Version.CURRENT);
Version oldVersion = VersionUtils.randomVersionBetween(random(), Version.V_8_0_0, Version.V_8_1_0);
assertSerialization(query, newVersion);
assertSerialization(queryWithNoFilters, oldVersion);
try (BytesStreamOutput output = new BytesStreamOutput()) {
output.setVersion(newVersion);
output.writeNamedWriteable(query);
try (StreamInput in = new NamedWriteableAwareStreamInput(output.bytes().streamInput(), namedWriteableRegistry())) {
in.setVersion(oldVersion);
KnnVectorQueryBuilder deserializedQuery = (KnnVectorQueryBuilder) in.readNamedWriteable(QueryBuilder.class);
assertEquals(queryWithNoFilters, deserializedQuery);
assertEquals(queryWithNoFilters.hashCode(), deserializedQuery.hashCode());
}
}
}
@Override
public void testUnknownObjectException() throws IOException {
// Test isn't relevant, since query is never parsed from xContent
}
@Override
public void testFromXContent() throws IOException {
// Test isn't relevant, since query is never parsed from xContent
}
@Override
public void testUnknownField() throws IOException {
// Test isn't relevant, since query is never parsed from xContent
} }
} }

View file

@ -7,6 +7,7 @@
package org.elasticsearch.index.engine.frozen; package org.elasticsearch.index.engine.frozen;
import org.apache.lucene.index.BinaryDocValues; import org.apache.lucene.index.BinaryDocValues;
import org.apache.lucene.index.ByteVectorValues;
import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.FieldInfo; import org.apache.lucene.index.FieldInfo;
import org.apache.lucene.index.FieldInfos; import org.apache.lucene.index.FieldInfos;
@ -22,11 +23,14 @@ import org.apache.lucene.index.SortedDocValues;
import org.apache.lucene.index.SortedNumericDocValues; import org.apache.lucene.index.SortedNumericDocValues;
import org.apache.lucene.index.SortedSetDocValues; import org.apache.lucene.index.SortedSetDocValues;
import org.apache.lucene.index.StoredFieldVisitor; import org.apache.lucene.index.StoredFieldVisitor;
import org.apache.lucene.index.StoredFields;
import org.apache.lucene.index.TermVectors;
import org.apache.lucene.index.Terms; import org.apache.lucene.index.Terms;
import org.apache.lucene.index.VectorValues; import org.apache.lucene.index.VectorValues;
import org.apache.lucene.search.TopDocs; import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory; import org.apache.lucene.store.Directory;
import org.apache.lucene.util.Bits; import org.apache.lucene.util.Bits;
import org.apache.lucene.util.BytesRef;
import java.io.IOException; import java.io.IOException;
import java.util.Comparator; import java.util.Comparator;
@ -216,11 +220,21 @@ final class RewriteCachingDirectoryReader extends DirectoryReader {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public ByteVectorValues getByteVectorValues(String field) throws IOException {
throw new UnsupportedOperationException();
}
@Override @Override
public TopDocs searchNearestVectors(String field, float[] target, int k, Bits acceptDocs, int visitedLimit) throws IOException { public TopDocs searchNearestVectors(String field, float[] target, int k, Bits acceptDocs, int visitedLimit) throws IOException {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public TopDocs searchNearestVectors(String field, BytesRef target, int k, Bits acceptDocs, int visitedLimit) throws IOException {
throw new UnsupportedOperationException();
}
@Override @Override
public FieldInfos getFieldInfos() { public FieldInfos getFieldInfos() {
return fieldInfos; return fieldInfos;
@ -249,6 +263,16 @@ final class RewriteCachingDirectoryReader extends DirectoryReader {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public TermVectors termVectors() throws IOException {
throw new UnsupportedOperationException();
}
@Override
public StoredFields storedFields() throws IOException {
throw new UnsupportedOperationException();
}
@Override @Override
public int numDocs() { public int numDocs() {
return numDocs; return numDocs;

View file

@ -8,6 +8,7 @@ package org.elasticsearch.xpack.core.security.authz.accesscontrol;
import org.apache.lucene.codecs.StoredFieldsReader; import org.apache.lucene.codecs.StoredFieldsReader;
import org.apache.lucene.index.BinaryDocValues; import org.apache.lucene.index.BinaryDocValues;
import org.apache.lucene.index.ByteVectorValues;
import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.FieldInfo; import org.apache.lucene.index.FieldInfo;
import org.apache.lucene.index.FieldInfos; import org.apache.lucene.index.FieldInfos;
@ -21,7 +22,9 @@ import org.apache.lucene.index.SortedDocValues;
import org.apache.lucene.index.SortedNumericDocValues; import org.apache.lucene.index.SortedNumericDocValues;
import org.apache.lucene.index.SortedSetDocValues; import org.apache.lucene.index.SortedSetDocValues;
import org.apache.lucene.index.StoredFieldVisitor; import org.apache.lucene.index.StoredFieldVisitor;
import org.apache.lucene.index.StoredFields;
import org.apache.lucene.index.TermState; import org.apache.lucene.index.TermState;
import org.apache.lucene.index.TermVectors;
import org.apache.lucene.index.Terms; import org.apache.lucene.index.Terms;
import org.apache.lucene.index.TermsEnum; import org.apache.lucene.index.TermsEnum;
import org.apache.lucene.index.VectorValues; import org.apache.lucene.index.VectorValues;
@ -162,6 +165,34 @@ public final class FieldSubsetReader extends SequentialStoredFieldsLeafReader {
return f.iterator().hasNext() ? f : null; return f.iterator().hasNext() ? f : null;
} }
@Override
public TermVectors termVectors() throws IOException {
TermVectors termVectors = super.termVectors();
return new TermVectors() {
@Override
public Fields get(int doc) throws IOException {
Fields f = termVectors.get(doc);
if (f == null) {
return null;
}
f = new FieldFilterFields(f);
// we need to check for emptyness, so we can return null:
return f.iterator().hasNext() ? f : null;
}
};
}
@Override
public StoredFields storedFields() throws IOException {
StoredFields storedFields = super.storedFields();
return new StoredFields() {
@Override
public void document(int docID, StoredFieldVisitor visitor) throws IOException {
storedFields.document(docID, new FieldSubsetStoredFieldVisitor(visitor));
}
};
}
/** Filter a map by a {@link CharacterRunAutomaton} that defines the fields to retain. */ /** Filter a map by a {@link CharacterRunAutomaton} that defines the fields to retain. */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
static Map<String, Object> filter(Map<String, ?> map, CharacterRunAutomaton includeAutomaton, int initialState) { static Map<String, Object> filter(Map<String, ?> map, CharacterRunAutomaton includeAutomaton, int initialState) {
@ -287,6 +318,16 @@ public final class FieldSubsetReader extends SequentialStoredFieldsLeafReader {
return hasField(field) ? super.searchNearestVectors(field, target, k, acceptDocs, visitedLimit) : null; return hasField(field) ? super.searchNearestVectors(field, target, k, acceptDocs, visitedLimit) : null;
} }
@Override
public ByteVectorValues getByteVectorValues(String field) throws IOException {
return hasField(field) ? super.getByteVectorValues(field) : null;
}
@Override
public TopDocs searchNearestVectors(String field, BytesRef target, int k, Bits acceptDocs, int visitedLimit) throws IOException {
return hasField(field) ? super.searchNearestVectors(field, target, k, acceptDocs, visitedLimit) : null;
}
// we share core cache keys (for e.g. fielddata) // we share core cache keys (for e.g. fielddata)
@Override @Override
@ -310,8 +351,8 @@ public final class FieldSubsetReader extends SequentialStoredFieldsLeafReader {
} }
@Override @Override
public void visitDocument(int docID, StoredFieldVisitor visitor) throws IOException { public void document(int docID, StoredFieldVisitor visitor) throws IOException {
reader.visitDocument(docID, new FieldSubsetStoredFieldVisitor(visitor)); reader.document(docID, new FieldSubsetStoredFieldVisitor(visitor));
} }
@Override @Override

View file

@ -11,6 +11,7 @@ import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field; import org.apache.lucene.document.Field;
import org.apache.lucene.document.FieldType; import org.apache.lucene.document.FieldType;
import org.apache.lucene.document.IntPoint; import org.apache.lucene.document.IntPoint;
import org.apache.lucene.document.KnnByteVectorField;
import org.apache.lucene.document.KnnVectorField; import org.apache.lucene.document.KnnVectorField;
import org.apache.lucene.document.NumericDocValuesField; import org.apache.lucene.document.NumericDocValuesField;
import org.apache.lucene.document.SortedDocValuesField; import org.apache.lucene.document.SortedDocValuesField;
@ -20,6 +21,7 @@ import org.apache.lucene.document.StoredField;
import org.apache.lucene.document.StringField; import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField; import org.apache.lucene.document.TextField;
import org.apache.lucene.index.BinaryDocValues; import org.apache.lucene.index.BinaryDocValues;
import org.apache.lucene.index.ByteVectorValues;
import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.FieldInfo; import org.apache.lucene.index.FieldInfo;
import org.apache.lucene.index.FieldInfos; import org.apache.lucene.index.FieldInfos;
@ -214,6 +216,39 @@ public class FieldSubsetReaderTests extends ESTestCase {
IOUtils.close(ir, iw, dir); IOUtils.close(ir, iw, dir);
} }
public void testKnnByteVectors() throws Exception {
Directory dir = newDirectory();
IndexWriterConfig iwc = new IndexWriterConfig(null);
IndexWriter iw = new IndexWriter(dir, iwc);
Document doc = new Document();
doc.add(new KnnByteVectorField("fieldA", new BytesRef(new byte[] { 1, 2, 3 })));
doc.add(new KnnByteVectorField("fieldB", new BytesRef(new byte[] { 3, 2, 1 })));
iw.addDocument(doc);
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), new CharacterRunAutomaton(Automata.makeString("fieldA")));
LeafReader leafReader = ir.leaves().get(0).reader();
// Check that fieldA behaves as normal
ByteVectorValues vectorValues = leafReader.getByteVectorValues("fieldA");
assertEquals(3, vectorValues.dimension());
assertEquals(1, vectorValues.size());
assertEquals(0, vectorValues.nextDoc());
assertNotNull(vectorValues.binaryValue());
assertNotNull(vectorValues.vectorValue());
TopDocs topDocs = leafReader.searchNearestVectors("fieldA", new BytesRef(new byte[] { 1, 1, 1 }), 5, null, Integer.MAX_VALUE);
assertNotNull(topDocs);
assertEquals(1, topDocs.scoreDocs.length);
// Check that we can't see fieldB
assertNull(leafReader.getByteVectorValues("fieldB"));
assertNull(leafReader.searchNearestVectors("fieldB", new BytesRef(new byte[] { 1, 1, 1 }), 5, null, Integer.MAX_VALUE));
TestUtil.checkReader(ir);
IOUtils.close(ir, iw, dir);
}
/** /**
* test filtering two stored fields (string) * test filtering two stored fields (string)
*/ */
@ -232,10 +267,16 @@ public class FieldSubsetReaderTests extends ESTestCase {
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), new CharacterRunAutomaton(Automata.makeString("fieldA"))); DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), new CharacterRunAutomaton(Automata.makeString("fieldA")));
// see only one field // see only one field
Document d2 = ir.document(0); {
assertEquals(1, d2.getFields().size()); Document d2 = ir.document(0);
assertEquals("testA", d2.get("fieldA")); assertEquals(1, d2.getFields().size());
assertEquals("testA", d2.get("fieldA"));
}
{
Document d2 = ir.storedFields().document(0);
assertEquals(1, d2.getFields().size());
assertEquals("testA", d2.get("fieldA"));
}
TestUtil.checkReader(ir); TestUtil.checkReader(ir);
IOUtils.close(ir, iw, dir); IOUtils.close(ir, iw, dir);
} }
@ -258,10 +299,16 @@ public class FieldSubsetReaderTests extends ESTestCase {
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), new CharacterRunAutomaton(Automata.makeString("fieldA"))); DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), new CharacterRunAutomaton(Automata.makeString("fieldA")));
// see only one field // see only one field
Document d2 = ir.document(0); {
assertEquals(1, d2.getFields().size()); Document d2 = ir.document(0);
assertEquals(new BytesRef("testA"), d2.getBinaryValue("fieldA")); assertEquals(1, d2.getFields().size());
assertEquals(new BytesRef("testA"), d2.getBinaryValue("fieldA"));
}
{
Document d2 = ir.storedFields().document(0);
assertEquals(1, d2.getFields().size());
assertEquals(new BytesRef("testA"), d2.getBinaryValue("fieldA"));
}
TestUtil.checkReader(ir); TestUtil.checkReader(ir);
IOUtils.close(ir, iw, dir); IOUtils.close(ir, iw, dir);
} }
@ -284,10 +331,16 @@ public class FieldSubsetReaderTests extends ESTestCase {
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), new CharacterRunAutomaton(Automata.makeString("fieldA"))); DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), new CharacterRunAutomaton(Automata.makeString("fieldA")));
// see only one field // see only one field
Document d2 = ir.document(0); {
assertEquals(1, d2.getFields().size()); Document d2 = ir.document(0);
assertEquals(1, d2.getField("fieldA").numericValue()); assertEquals(1, d2.getFields().size());
assertEquals(1, d2.getField("fieldA").numericValue());
}
{
Document d2 = ir.storedFields().document(0);
assertEquals(1, d2.getFields().size());
assertEquals(1, d2.getField("fieldA").numericValue());
}
TestUtil.checkReader(ir); TestUtil.checkReader(ir);
IOUtils.close(ir, iw, dir); IOUtils.close(ir, iw, dir);
} }
@ -310,10 +363,16 @@ public class FieldSubsetReaderTests extends ESTestCase {
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), new CharacterRunAutomaton(Automata.makeString("fieldA"))); DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), new CharacterRunAutomaton(Automata.makeString("fieldA")));
// see only one field // see only one field
Document d2 = ir.document(0); {
assertEquals(1, d2.getFields().size()); Document d2 = ir.document(0);
assertEquals(1L, d2.getField("fieldA").numericValue()); assertEquals(1, d2.getFields().size());
assertEquals(1L, d2.getField("fieldA").numericValue());
}
{
Document d2 = ir.storedFields().document(0);
assertEquals(1, d2.getFields().size());
assertEquals(1L, d2.getField("fieldA").numericValue());
}
TestUtil.checkReader(ir); TestUtil.checkReader(ir);
IOUtils.close(ir, iw, dir); IOUtils.close(ir, iw, dir);
} }
@ -336,10 +395,16 @@ public class FieldSubsetReaderTests extends ESTestCase {
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), new CharacterRunAutomaton(Automata.makeString("fieldA"))); DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), new CharacterRunAutomaton(Automata.makeString("fieldA")));
// see only one field // see only one field
Document d2 = ir.document(0); {
assertEquals(1, d2.getFields().size()); Document d2 = ir.document(0);
assertEquals(1F, d2.getField("fieldA").numericValue()); assertEquals(1, d2.getFields().size());
assertEquals(1F, d2.getField("fieldA").numericValue());
}
{
Document d2 = ir.storedFields().document(0);
assertEquals(1, d2.getFields().size());
assertEquals(1F, d2.getField("fieldA").numericValue());
}
TestUtil.checkReader(ir); TestUtil.checkReader(ir);
IOUtils.close(ir, iw, dir); IOUtils.close(ir, iw, dir);
} }
@ -362,10 +427,16 @@ public class FieldSubsetReaderTests extends ESTestCase {
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), new CharacterRunAutomaton(Automata.makeString("fieldA"))); DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), new CharacterRunAutomaton(Automata.makeString("fieldA")));
// see only one field // see only one field
Document d2 = ir.document(0); {
assertEquals(1, d2.getFields().size()); Document d2 = ir.document(0);
assertEquals(1D, d2.getField("fieldA").numericValue()); assertEquals(1, d2.getFields().size());
assertEquals(1D, d2.getField("fieldA").numericValue());
}
{
Document d2 = ir.storedFields().document(0);
assertEquals(1, d2.getFields().size());
assertEquals(1D, d2.getField("fieldA").numericValue());
}
TestUtil.checkReader(ir); TestUtil.checkReader(ir);
IOUtils.close(ir, iw, dir); IOUtils.close(ir, iw, dir);
} }
@ -624,10 +695,16 @@ public class FieldSubsetReaderTests extends ESTestCase {
DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), new CharacterRunAutomaton(automaton)); DirectoryReader ir = FieldSubsetReader.wrap(DirectoryReader.open(iw), new CharacterRunAutomaton(automaton));
// see only one field // see only one field
Document d2 = ir.document(0); {
assertEquals(1, d2.getFields().size()); Document d2 = ir.document(0);
assertEquals("{\"fieldA\":\"testA\"}", d2.getBinaryValue(SourceFieldMapper.NAME).utf8ToString()); assertEquals(1, d2.getFields().size());
assertEquals("{\"fieldA\":\"testA\"}", d2.getBinaryValue(SourceFieldMapper.NAME).utf8ToString());
}
{
Document d2 = ir.storedFields().document(0);
assertEquals(1, d2.getFields().size());
assertEquals("{\"fieldA\":\"testA\"}", d2.getBinaryValue(SourceFieldMapper.NAME).utf8ToString());
}
TestUtil.checkReader(ir); TestUtil.checkReader(ir);
IOUtils.close(ir, iw, dir); IOUtils.close(ir, iw, dir);
} }
@ -1025,11 +1102,17 @@ public class FieldSubsetReaderTests extends ESTestCase {
// see no vectors // see no vectors
assertNull(segmentReader.getTermVectors(0)); assertNull(segmentReader.getTermVectors(0));
assertNull(segmentReader.termVectors().get(0));
// see no stored fields // see no stored fields
Document document = segmentReader.document(0); {
assertEquals(0, document.getFields().size()); Document document = segmentReader.document(0);
assertEquals(0, document.getFields().size());
}
{
Document document = segmentReader.storedFields().document(0);
assertEquals(0, document.getFields().size());
}
TestUtil.checkReader(ir); TestUtil.checkReader(ir);
IOUtils.close(ir, iw, dir); IOUtils.close(ir, iw, dir);
} }

View file

@ -11,8 +11,8 @@ import org.apache.lucene.document.Field;
import org.apache.lucene.document.LongPoint; import org.apache.lucene.document.LongPoint;
import org.apache.lucene.document.SortedNumericDocValuesField; import org.apache.lucene.document.SortedNumericDocValuesField;
import org.apache.lucene.document.StoredField; import org.apache.lucene.document.StoredField;
import org.apache.lucene.sandbox.search.IndexSortSortedNumericDocValuesRangeQuery;
import org.apache.lucene.search.IndexOrDocValuesQuery; import org.apache.lucene.search.IndexOrDocValuesQuery;
import org.apache.lucene.search.IndexSortSortedNumericDocValuesRangeQuery;
import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRef;