Skip to content

Commit 2d7062b

Browse files
authored
Merge branch 'main' into inference-command-options
2 parents 0ef4c9e + c04e6e5 commit 2d7062b

File tree

22 files changed

+628
-677
lines changed

22 files changed

+628
-677
lines changed

docs/changelog/131517.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 131517
2+
summary: Refresh potential lost connections at query start for field caps
3+
area: Search
4+
type: enhancement
5+
issues: []

docs/reference/elasticsearch/mapping-reference/semantic-text.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,14 @@ the embedding generation, indexing, and query to use.
3737
[quantized](/reference/elasticsearch/mapping-reference/dense-vector.md#dense-vector-quantization)
3838
to `bbq_hnsw` automatically.
3939

40+
## Default and custom endpoints
41+
42+
You can use either preconfigured endpoints in your `semantic_text` fields which
43+
are ideal for most use cases or create custom endpoints and reference them in
44+
the field mappings.
45+
46+
### Using the default ELSER endpoint
47+
4048
If you use the preconfigured `.elser-2-elasticsearch` endpoint, you can set up
4149
`semantic_text` with the following API request:
4250

@@ -53,6 +61,8 @@ PUT my-index-000001
5361
}
5462
```
5563

64+
### Using a custom endpoint
65+
5666
To use a custom {{infer}} endpoint instead of the default
5767
`.elser-2-elasticsearch`, you
5868
must [Create {{infer}} API](https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put)
@@ -96,6 +106,35 @@ PUT my-index-000003
96106
}
97107
```
98108

109+
### Using ELSER on EIS
110+
111+
```{applies_to}
112+
stack: preview 9.1
113+
serverless: preview
114+
```
115+
116+
If you use the preconfigured `.elser-2-elastic` endpoint that utilizes the ELSER model as a service through the Elastic Inference Service ([ELSER on EIS](docs-content://explore-analyze/elastic-inference/eis.md#elser-on-eis)), you can
117+
set up `semantic_text` with the following API request:
118+
119+
```console
120+
PUT my-index-000001
121+
{
122+
"mappings": {
123+
"properties": {
124+
"inference_field": {
125+
"type": "semantic_text",
126+
"inference_id": ".elser-2-elastic"
127+
}
128+
}
129+
}
130+
}
131+
```
132+
133+
::::{note}
134+
While we do encourage experimentation, we do not recommend implementing production use cases on top of this feature while it is in Technical Preview.
135+
136+
::::
137+
99138
## Parameters for `semantic_text` fields [semantic-text-params]
100139

101140
`inference_id`

muted-tests.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,12 @@ tests:
614614
- class: org.elasticsearch.index.mapper.vectors.DenseVectorFieldIndexTypeUpdateIT
615615
method: "testDenseVectorMappingUpdate {initialType=bbq_hnsw updateType=bbq_disk #2}"
616616
issue: https://github.com/elastic/elasticsearch/issues/132152
617+
- class: org.elasticsearch.index.mapper.vectors.DenseVectorFieldIndexTypeUpdateIT
618+
method: testDenseVectorMappingUpdate {initialType=hnsw updateType=int8_hnsw}
619+
issue: https://github.com/elastic/elasticsearch/issues/132164
620+
- class: org.elasticsearch.index.mapper.vectors.DenseVectorFieldIndexTypeUpdateIT
621+
method: testDenseVectorMappingUpdate {initialType=int4_hnsw updateType=bbq_disk}
622+
issue: https://github.com/elastic/elasticsearch/issues/132165
617623

618624
# Examples:
619625
#
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
package org.elasticsearch.indices.cluster;
11+
12+
import org.elasticsearch.ElasticsearchTimeoutException;
13+
import org.elasticsearch.ExceptionsHelper;
14+
import org.elasticsearch.action.fieldcaps.FieldCapabilitiesRequest;
15+
import org.elasticsearch.action.fieldcaps.TransportFieldCapabilitiesAction;
16+
import org.elasticsearch.common.settings.Setting;
17+
import org.elasticsearch.common.settings.Settings;
18+
import org.elasticsearch.common.util.CollectionUtils;
19+
import org.elasticsearch.plugins.ClusterPlugin;
20+
import org.elasticsearch.plugins.Plugin;
21+
import org.elasticsearch.test.AbstractMultiClustersTestCase;
22+
import org.elasticsearch.test.transport.MockTransportService;
23+
import org.elasticsearch.transport.TransportService;
24+
import org.hamcrest.Matchers;
25+
26+
import java.util.Collection;
27+
import java.util.List;
28+
import java.util.Map;
29+
import java.util.concurrent.CountDownLatch;
30+
31+
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
32+
33+
public class FieldCapsForceConnectTimeoutIT extends AbstractMultiClustersTestCase {
34+
private static final String LINKED_CLUSTER_1 = "cluster-a";
35+
private static final String LINKED_CLUSTER_2 = "cluster-b";
36+
37+
public static class ForceConnectTimeoutPlugin extends Plugin implements ClusterPlugin {
38+
@Override
39+
public List<Setting<?>> getSettings() {
40+
return List.of(ForceConnectTimeoutSetting);
41+
}
42+
}
43+
44+
private static final Setting<String> ForceConnectTimeoutSetting = Setting.simpleString(
45+
"search.ccs.force_connect_timeout",
46+
Setting.Property.NodeScope
47+
);
48+
49+
@Override
50+
protected List<String> remoteClusterAlias() {
51+
return List.of(LINKED_CLUSTER_1, LINKED_CLUSTER_2);
52+
}
53+
54+
@Override
55+
protected Collection<Class<? extends Plugin>> nodePlugins(String clusterAlias) {
56+
return CollectionUtils.appendToCopy(super.nodePlugins(clusterAlias), ForceConnectTimeoutPlugin.class);
57+
}
58+
59+
@Override
60+
protected Settings nodeSettings() {
61+
/*
62+
* This is the setting that controls how long TransportFieldCapabilitiesAction will wait for establishing a connection
63+
* with a remote. At present, we set it to low 1s to prevent stalling the test for too long -- this is consistent
64+
* with what we've done in other tests.
65+
*/
66+
return Settings.builder().put(super.nodeSettings()).put("search.ccs.force_connect_timeout", "1s").build();
67+
}
68+
69+
@Override
70+
protected Map<String, Boolean> skipUnavailableForRemoteClusters() {
71+
return Map.of(LINKED_CLUSTER_1, true, LINKED_CLUSTER_2, true);
72+
}
73+
74+
public void testTimeoutSetting() {
75+
var latch = new CountDownLatch(1);
76+
for (String nodeName : cluster(LOCAL_CLUSTER).getNodeNames()) {
77+
MockTransportService mts = (MockTransportService) cluster(LOCAL_CLUSTER).getInstance(TransportService.class, nodeName);
78+
79+
mts.addConnectBehavior(
80+
cluster(LINKED_CLUSTER_1).getInstance(TransportService.class, (String) null),
81+
((transport, discoveryNode, profile, listener) -> {
82+
try {
83+
latch.await();
84+
} catch (InterruptedException e) {
85+
throw new AssertionError(e);
86+
}
87+
88+
transport.openConnection(discoveryNode, profile, listener);
89+
})
90+
);
91+
}
92+
93+
// Add some dummy data to prove we are communicating fine with the remote.
94+
assertAcked(client(LINKED_CLUSTER_1).admin().indices().prepareCreate("test-index"));
95+
client(LINKED_CLUSTER_1).prepareIndex("test-index").setSource("sample-field", "sample-value").get();
96+
client(LINKED_CLUSTER_1).admin().indices().prepareRefresh("test-index").get();
97+
98+
/*
99+
* Do a full restart so that our custom connect behaviour takes effect since it does not apply to
100+
* pre-existing connections -- they're already established by the time this test runs.
101+
*/
102+
try {
103+
cluster(LINKED_CLUSTER_1).fullRestart();
104+
} catch (Exception e) {
105+
throw new AssertionError(e);
106+
} finally {
107+
var fieldCapsRequest = new FieldCapabilitiesRequest();
108+
/*
109+
* We have an origin and 2 linked clusters but will target only the one that we stalled.
110+
* This is because when the timeout kicks in, and we move on from the stalled cluster, we do not want
111+
* the error to be a top-level error. Rather, it must be present in the response object under "failures".
112+
* All other errors are free to be top-level errors though.
113+
*/
114+
fieldCapsRequest.indices(LINKED_CLUSTER_1 + ":*");
115+
fieldCapsRequest.fields("foo", "bar", "baz");
116+
var result = safeGet(client().execute(TransportFieldCapabilitiesAction.TYPE, fieldCapsRequest));
117+
118+
var failures = result.getFailures();
119+
assertThat(failures.size(), Matchers.is(1));
120+
121+
var failure = failures.getFirst();
122+
assertThat(failure.getIndices().length, Matchers.is(1));
123+
assertThat(failure.getIndices()[0], Matchers.equalTo("cluster-a:*"));
124+
// Outer wrapper that gets unwrapped in ExceptionsHelper.isRemoteUnavailableException().
125+
assertThat(
126+
failure.getException().toString(),
127+
Matchers.containsString("java.lang.IllegalStateException: Unable to open any connections")
128+
);
129+
130+
// The actual error that is thrown by the subscribable listener when a linked cluster could not be talked to.
131+
assertThat(failure.getException().getCause(), Matchers.instanceOf(ElasticsearchTimeoutException.class));
132+
assertThat(ExceptionsHelper.isRemoteUnavailableException(failure.getException()), Matchers.is(true));
133+
134+
latch.countDown();
135+
result.decRef();
136+
}
137+
}
138+
}

0 commit comments

Comments
 (0)