Skip to content

Commit 9b7728e

Browse files
authored
Merge branch 'main' into esql_auto_partition
2 parents 409067c + 591fa87 commit 9b7728e

File tree

51 files changed

+2281
-837
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+2281
-837
lines changed

docs/changelog/126385.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pr: 126385
2+
summary: Filter out empty top docs results before merging
3+
area: Search
4+
type: bug
5+
issues:
6+
- 126118

docs/release-notes/index.md

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,29 +25,25 @@ To check for security updates, go to [Security announcements for the Elastic sta
2525

2626
### Highlights [elasticsearch-900-highlights]
2727

28-
::::{dropdown} Add new experimental `rank_vectors` mapping for late-interaction second order ranking
29-
Late-interaction models are powerful rerankers. While their size and overall cost doesn't lend itself for HNSW indexing, utilizing them as second order reranking can provide excellent boosts in relevance. The new `rank_vectors` mapping allows for rescoring over new and novel multi-vector late-interaction models like ColBERT or ColPali.
28+
::::{dropdown} rank_vectors field type is now available for late-interaction ranking
3029

31-
For more information, check [PR #118804](https://github.com/elastic/elasticsearch/pull/118804).
32-
::::
30+
[`rank_vectors`](../reference/elasticsearch/mapping-reference/rank-vectors.md) is a new field type released as an experimental feature in Elasticsearch 9.0. It is designed to be used with dense vectors and allows for late-interaction second order ranking.
3331

34-
::::{dropdown} Enable LOOKUP JOIN in non-snapshot builds
35-
This effectively releases LOOKUP JOIN into tech preview. Docs will
36-
follow in a separate PR.
32+
Late-interaction models are powerful rerankers. While their size and overall cost doesn’t lend itself for HNSW indexing, utilizing them as second order reranking can provide excellent boosts in relevance. The new `rank_vectors` mapping allows for rescoring over new and novel multi-vector late-interaction models like ColBERT or ColPali.
33+
::::
3734

38-
- Enable the lexing/grammar for LOOKUP JOIN in non-snapshot builds.
39-
- Remove the grammar for the unsupported `| JOIN ...` command (without `LOOKUP` as first keyword). The way the lexer modes work, otherwise we'd also have to enable `| JOIN ...` syntax on non-snapshot builds and would have to add additional validation to provide appropriate error messages.
40-
- Remove grammar for `LOOKUP JOIN index AS ...` because qualifiers are not yet supported. Otherwise we'd have to put in additional validation as well to prevent such queries.
35+
::::{dropdown} ES|QL LOOKUP JOIN is now available in technical preview
4136

42-
Also fix https://github.com/elastic/elasticsearch/issues/121185
37+
[LOOKUP JOIN](../reference/query-languages/esql/esql-commands.md) is now available in technical preview. LOOKUP JOIN combines data from your ES|QL queries with matching records from a lookup index, enabling you to:
4338

44-
For more information, check [PR #121193](https://github.com/elastic/elasticsearch/pull/121193).
39+
- Enrich your search results with reference data
40+
- Speed up root-cause analysis and security investigations
41+
- Join data across indices without complex queries
42+
- Reduce operational overhead when correlating events
4543
::::
4644

47-
::::{dropdown} Release semantic_text as a GA feature
48-
semantic_text is now an official GA (generally available) feature! This field type allows you to easily set up and perform semantic search with minimal ramp up time.
49-
50-
For more information, check [PR #124669](https://github.com/elastic/elasticsearch/pull/124669).
45+
::::{dropdown} The semantic_text field type is now GA
46+
[`semantic_text`](../reference/elasticsearch/mapping-reference/semantic-text.md) is now an official GA (generally available) feature! This field type allows you to easily set up and perform semantic search with minimal ramp up time.
5147
::::
5248

5349
### Features and enhancements [elasticsearch-900-features-enhancements]

muted-tests.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,9 @@ tests:
432432
- class: org.elasticsearch.repositories.blobstore.testkit.rest.SnapshotRepoTestKitClientYamlTestSuiteIT
433433
method: test {p0=/10_analyze/Analysis without details}
434434
issue: https://github.com/elastic/elasticsearch/issues/126569
435+
- class: org.elasticsearch.repositories.blobstore.testkit.analyze.S3RepositoryAnalysisRestIT
436+
method: testRepositoryAnalysis
437+
issue: https://github.com/elastic/elasticsearch/issues/126576
435438

436439
# Examples:
437440
#

server/src/internalClusterTest/java/org/elasticsearch/index/shard/IndexShardIT.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,7 @@ public void testInvalidateIndicesRequestCacheWhenRollbackEngine() throws Excepti
676676
final CountDownLatch engineResetLatch = new CountDownLatch(1);
677677
shard.acquireAllPrimaryOperationsPermits(ActionListener.wrap(r -> {
678678
try {
679-
shard.resetEngineToGlobalCheckpoint();
679+
shard.rollbackEngineToGlobalCheckpoint();
680680
} finally {
681681
r.close();
682682
engineResetLatch.countDown();

server/src/internalClusterTest/java/org/elasticsearch/indices/IndexingMemoryControllerIT.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ EngineConfig engineConfigWithLargerIndexingMemory(EngineConfig config) {
8484
config.getRelativeTimeInNanosSupplier(),
8585
config.getIndexCommitListener(),
8686
config.isPromotableToPrimary(),
87-
config.getMapperService()
87+
config.getMapperService(),
88+
config.getEngineResetLock()
8889
);
8990
}
9091

server/src/internalClusterTest/java/org/elasticsearch/snapshots/SharedClusterSnapshotRestoreIT.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -748,7 +748,7 @@ public void testDeletionOfFailingToRecoverIndexShouldStopRestore() throws Except
748748

749749
logger.info("--> wait for the index to appear");
750750
// that would mean that recovery process started and failing
751-
safeGet(clusterAdmin().prepareHealth(SAFE_AWAIT_TIMEOUT, "test-idx").execute());
751+
awaitIndexExists("test-idx");
752752

753753
logger.info("--> delete index");
754754
cluster().wipeIndices("test-idx");

server/src/main/java/org/elasticsearch/action/search/SearchPhaseController.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,11 +150,11 @@ static TopDocs mergeTopDocs(List<TopDocs> results, int topN, int from) {
150150
return topDocs;
151151
} else if (topDocs instanceof TopFieldGroups firstTopDocs) {
152152
final Sort sort = new Sort(firstTopDocs.fields);
153-
final TopFieldGroups[] shardTopDocs = results.toArray(new TopFieldGroups[0]);
153+
final TopFieldGroups[] shardTopDocs = results.stream().filter(td -> td != Lucene.EMPTY_TOP_DOCS).toArray(TopFieldGroups[]::new);
154154
mergedTopDocs = TopFieldGroups.merge(sort, from, topN, shardTopDocs, false);
155155
} else if (topDocs instanceof TopFieldDocs firstTopDocs) {
156156
final Sort sort = checkSameSortTypes(results, firstTopDocs.fields);
157-
final TopFieldDocs[] shardTopDocs = results.toArray(new TopFieldDocs[0]);
157+
final TopFieldDocs[] shardTopDocs = results.stream().filter((td -> td != Lucene.EMPTY_TOP_DOCS)).toArray(TopFieldDocs[]::new);
158158
mergedTopDocs = TopDocs.merge(sort, from, topN, shardTopDocs);
159159
} else {
160160
final TopDocs[] shardTopDocs = results.toArray(new TopDocs[numShards]);

server/src/main/java/org/elasticsearch/index/engine/Engine.java

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import org.elasticsearch.common.util.concurrent.ReleasableLock;
5353
import org.elasticsearch.common.util.concurrent.UncategorizedExecutionException;
5454
import org.elasticsearch.core.AbstractRefCounted;
55+
import org.elasticsearch.core.Assertions;
5556
import org.elasticsearch.core.CheckedRunnable;
5657
import org.elasticsearch.core.Nullable;
5758
import org.elasticsearch.core.RefCounted;
@@ -76,6 +77,7 @@
7677
import org.elasticsearch.index.seqno.SequenceNumbers;
7778
import org.elasticsearch.index.shard.DenseVectorStats;
7879
import org.elasticsearch.index.shard.DocsStats;
80+
import org.elasticsearch.index.shard.EngineResetLock;
7981
import org.elasticsearch.index.shard.IndexShard;
8082
import org.elasticsearch.index.shard.ShardFieldStats;
8183
import org.elasticsearch.index.shard.ShardId;
@@ -1288,7 +1290,7 @@ public void externalRefresh(String source, ActionListener<Engine.RefreshResult>
12881290

12891291
/**
12901292
* Asynchronously refreshes the engine for new search operations to reflect the latest
1291-
* changes unless another thread is already refreshing the engine concurrently.
1293+
* changes unless another thread is already refreshing or reseting the engine concurrently.
12921294
*/
12931295
@Nullable
12941296
public abstract void maybeRefresh(String source, ActionListener<RefreshResult> listener) throws EngineException;
@@ -2371,7 +2373,7 @@ public record FlushResult(boolean flushPerformed, long generation) {
23712373
}
23722374

23732375
/**
2374-
* Ensures the engine is in a state that it can be closed by a call to {@link IndexShard#resetEngine()}.
2376+
* Ensures the engine is in a state that it can be closed by a call to {@link IndexShard#resetEngine(Consumer<Engine>)}.
23752377
*
23762378
* In general, resetting the engine should be done with care, to consider any
23772379
* in-progress operations and listeners (e.g., primary term and generation listeners).
@@ -2384,4 +2386,36 @@ public void prepareForEngineReset() throws IOException {
23842386
public long getLastUnsafeSegmentGenerationForGets() {
23852387
throw new UnsupportedOperationException("Doesn't support getting the latest segment generation");
23862388
}
2389+
2390+
protected static <R extends ReferenceManager<ElasticsearchDirectoryReader>> R wrapForAssertions(
2391+
R referenceManager,
2392+
EngineConfig engineConfig
2393+
) {
2394+
if (Assertions.ENABLED) {
2395+
referenceManager.addListener(new AssertRefreshListenerHoldsEngineReadLock(engineConfig.getEngineResetLock()));
2396+
}
2397+
return referenceManager;
2398+
}
2399+
2400+
/**
2401+
* RefreshListener that asserts that the engine read lock is held by the thread refreshing the reference.
2402+
*/
2403+
private static class AssertRefreshListenerHoldsEngineReadLock implements ReferenceManager.RefreshListener {
2404+
2405+
private final EngineResetLock engineLock;
2406+
2407+
private AssertRefreshListenerHoldsEngineReadLock(EngineResetLock engineLock) {
2408+
this.engineLock = Objects.requireNonNull(engineLock);
2409+
}
2410+
2411+
@Override
2412+
public void beforeRefresh() throws IOException {
2413+
assert engineLock.isReadLockedByCurrentThread() : Thread.currentThread();
2414+
}
2415+
2416+
@Override
2417+
public void afterRefresh(boolean didRefresh) throws IOException {
2418+
assert engineLock.isReadLockedByCurrentThread() : Thread.currentThread();
2419+
}
2420+
}
23872421
}

server/src/main/java/org/elasticsearch/index/engine/EngineConfig.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.elasticsearch.index.codec.CodecService;
3030
import org.elasticsearch.index.mapper.MapperService;
3131
import org.elasticsearch.index.seqno.RetentionLeases;
32+
import org.elasticsearch.index.shard.EngineResetLock;
3233
import org.elasticsearch.index.shard.ShardId;
3334
import org.elasticsearch.index.store.Store;
3435
import org.elasticsearch.index.translog.TranslogConfig;
@@ -146,6 +147,8 @@ public Supplier<RetentionLeases> retentionLeasesSupplier() {
146147

147148
private final boolean promotableToPrimary;
148149

150+
private final EngineResetLock engineResetLock;
151+
149152
/**
150153
* Creates a new {@link org.elasticsearch.index.engine.EngineConfig}
151154
*/
@@ -177,7 +180,8 @@ public EngineConfig(
177180
LongSupplier relativeTimeInNanosSupplier,
178181
Engine.IndexCommitListener indexCommitListener,
179182
boolean promotableToPrimary,
180-
MapperService mapperService
183+
MapperService mapperService,
184+
EngineResetLock engineResetLock
181185
) {
182186
this.shardId = shardId;
183187
this.indexSettings = indexSettings;
@@ -224,6 +228,7 @@ public EngineConfig(
224228
this.promotableToPrimary = promotableToPrimary;
225229
// always use compound on flush - reduces # of file-handles on refresh
226230
this.useCompoundFile = indexSettings.getSettings().getAsBoolean(USE_COMPOUND_FILE, true);
231+
this.engineResetLock = engineResetLock;
227232
}
228233

229234
/**
@@ -468,4 +473,8 @@ public boolean getUseCompoundFile() {
468473
public MapperService getMapperService() {
469474
return mapperService;
470475
}
476+
477+
public EngineResetLock getEngineResetLock() {
478+
return engineResetLock;
479+
}
471480
}

0 commit comments

Comments
 (0)