@@ -387,7 +387,7 @@ private DenseVectorIndexOptions defaultIndexOptions(boolean defaultInt8Hnsw, boo
387
387
return new BBQHnswIndexOptions (
388
388
Lucene99HnswVectorsFormat .DEFAULT_MAX_CONN ,
389
389
Lucene99HnswVectorsFormat .DEFAULT_BEAM_WIDTH ,
390
- new RescoreVector ( DEFAULT_OVERSAMPLE )
390
+ null
391
391
);
392
392
} else if (defaultInt8Hnsw ) {
393
393
return new Int8HnswIndexOptions (
@@ -1632,9 +1632,6 @@ public DenseVectorIndexOptions parseIndexOptions(String fieldName, Map<String, ?
1632
1632
RescoreVector rescoreVector = null ;
1633
1633
if (hasRescoreIndexVersion (indexVersion )) {
1634
1634
rescoreVector = RescoreVector .fromIndexOptions (indexOptionsMap , indexVersion );
1635
- if (rescoreVector == null && defaultOversampleForBBQ (indexVersion )) {
1636
- rescoreVector = new RescoreVector (DEFAULT_OVERSAMPLE );
1637
- }
1638
1635
}
1639
1636
MappingParser .checkNoRemainingFields (fieldName , indexOptionsMap );
1640
1637
return new BBQHnswIndexOptions (m , efConstruction , rescoreVector );
@@ -1656,9 +1653,6 @@ public DenseVectorIndexOptions parseIndexOptions(String fieldName, Map<String, ?
1656
1653
RescoreVector rescoreVector = null ;
1657
1654
if (hasRescoreIndexVersion (indexVersion )) {
1658
1655
rescoreVector = RescoreVector .fromIndexOptions (indexOptionsMap , indexVersion );
1659
- if (rescoreVector == null && defaultOversampleForBBQ (indexVersion )) {
1660
- rescoreVector = new RescoreVector (DEFAULT_OVERSAMPLE );
1661
- }
1662
1656
}
1663
1657
MappingParser .checkNoRemainingFields (fieldName , indexOptionsMap );
1664
1658
return new BBQFlatIndexOptions (rescoreVector );
@@ -1693,9 +1687,6 @@ public DenseVectorIndexOptions parseIndexOptions(String fieldName, Map<String, ?
1693
1687
}
1694
1688
}
1695
1689
RescoreVector rescoreVector = RescoreVector .fromIndexOptions (indexOptionsMap , indexVersion );
1696
- if (rescoreVector == null ) {
1697
- rescoreVector = new RescoreVector (DEFAULT_OVERSAMPLE );
1698
- }
1699
1690
Object nProbeNode = indexOptionsMap .remove ("default_n_probe" );
1700
1691
int nProbe = -1 ;
1701
1692
if (nProbeNode != null ) {
@@ -2183,7 +2174,8 @@ public BBQHnswIndexOptions(int m, int efConstruction, RescoreVector rescoreVecto
2183
2174
@ Override
2184
2175
KnnVectorsFormat getVectorsFormat (ElementType elementType ) {
2185
2176
assert elementType == ElementType .FLOAT ;
2186
- return new ES818HnswBinaryQuantizedVectorsFormat (m , efConstruction );
2177
+ boolean directIO = rescoreVector .useDirectIO != null && rescoreVector .useDirectIO ;
2178
+ return new ES818HnswBinaryQuantizedVectorsFormat (m , efConstruction , directIO );
2187
2179
}
2188
2180
2189
2181
@ Override
@@ -2342,36 +2334,44 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
2342
2334
}
2343
2335
}
2344
2336
2345
- public record RescoreVector (float oversample ) implements ToXContentObject {
2337
+ public record RescoreVector (Float oversample , Boolean useDirectIO ) implements ToXContentObject {
2346
2338
static final String NAME = "rescore_vector" ;
2347
2339
static final String OVERSAMPLE = "oversample" ;
2340
+ static final String DIRECT_IO = "direct_io" ;
2348
2341
2349
2342
static RescoreVector fromIndexOptions (Map <String , ?> indexOptionsMap , IndexVersion indexVersion ) {
2350
2343
Object rescoreVectorNode = indexOptionsMap .remove (NAME );
2351
2344
if (rescoreVectorNode == null ) {
2352
2345
return null ;
2353
2346
}
2354
2347
Map <String , Object > mappedNode = XContentMapValues .nodeMapValue (rescoreVectorNode , NAME );
2348
+
2349
+ Float oversampleValue = null ;
2355
2350
Object oversampleNode = mappedNode .get (OVERSAMPLE );
2356
- if (oversampleNode == null ) {
2357
- throw new IllegalArgumentException ("Invalid rescore_vector value. Missing required field " + OVERSAMPLE );
2358
- }
2359
- float oversampleValue = (float ) XContentMapValues .nodeDoubleValue (oversampleNode );
2360
- if (oversampleValue == 0 && allowsZeroRescore (indexVersion ) == false ) {
2361
- throw new IllegalArgumentException ("oversample must be greater than 1" );
2362
- }
2363
- if (oversampleValue < 1 && oversampleValue != 0 ) {
2364
- throw new IllegalArgumentException ("oversample must be greater than 1 or exactly 0" );
2365
- } else if (oversampleValue > 10 ) {
2366
- throw new IllegalArgumentException ("oversample must be less than or equal to 10" );
2351
+ if (oversampleNode != null ) {
2352
+ oversampleValue = (float ) XContentMapValues .nodeDoubleValue (oversampleNode );
2353
+ if (oversampleValue == 0 && allowsZeroRescore (indexVersion ) == false ) {
2354
+ throw new IllegalArgumentException ("oversample must be greater than 1" );
2355
+ }
2356
+ if (oversampleValue < 1 && oversampleValue != 0 ) {
2357
+ throw new IllegalArgumentException ("oversample must be greater than 1 or exactly 0" );
2358
+ } else if (oversampleValue > 10 ) {
2359
+ throw new IllegalArgumentException ("oversample must be less than or equal to 10" );
2360
+ }
2367
2361
}
2368
- return new RescoreVector (oversampleValue );
2362
+
2363
+ Boolean directIO = (Boolean ) mappedNode .get (DIRECT_IO );
2364
+
2365
+ return new RescoreVector (oversampleValue , directIO );
2369
2366
}
2370
2367
2371
2368
@ Override
2372
2369
public XContentBuilder toXContent (XContentBuilder builder , Params params ) throws IOException {
2373
2370
builder .startObject (NAME );
2374
2371
builder .field (OVERSAMPLE , oversample );
2372
+ if (useDirectIO ) {
2373
+ builder .field (DIRECT_IO , useDirectIO );
2374
+ }
2375
2375
builder .endObject ();
2376
2376
return builder ;
2377
2377
}
@@ -2710,6 +2710,10 @@ && isNotUnitVector(squaredMagnitude)) {
2710
2710
&& quantizedIndexOptions .rescoreVector != null ) {
2711
2711
oversample = quantizedIndexOptions .rescoreVector .oversample ;
2712
2712
}
2713
+ if (oversample == null ) {
2714
+ oversample = DEFAULT_OVERSAMPLE ;
2715
+ }
2716
+
2713
2717
boolean rescore = needsRescore (oversample );
2714
2718
if (rescore ) {
2715
2719
// Will get k * oversample for rescoring, and get the top k
0 commit comments