Skip to content

Commit 1d11407

Browse files
authored
Add analyze API to high-level rest client (#31577)
1 parent 093ea03 commit 1d11407

File tree

11 files changed

+720
-8
lines changed

11 files changed

+720
-8
lines changed

client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java

+30
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
2424
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse;
2525
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
26+
import org.elasticsearch.action.admin.indices.analyze.AnalyzeRequest;
27+
import org.elasticsearch.action.admin.indices.analyze.AnalyzeResponse;
2628
import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest;
2729
import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheResponse;
2830
import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
@@ -752,4 +754,32 @@ public void getTemplateAsync(GetIndexTemplatesRequest getIndexTemplatesRequest,
752754
restHighLevelClient.performRequestAsyncAndParseEntity(getIndexTemplatesRequest, RequestConverters::getTemplates,
753755
options, GetIndexTemplatesResponse::fromXContent, listener, emptySet());
754756
}
757+
758+
/**
759+
* Calls the analyze API
760+
*
761+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-analyze.html">Analyze API on elastic.co</a>
762+
*
763+
* @param request the request
764+
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
765+
*/
766+
public AnalyzeResponse analyze(AnalyzeRequest request, RequestOptions options) throws IOException {
767+
return restHighLevelClient.performRequestAndParseEntity(request, RequestConverters::analyze, options,
768+
AnalyzeResponse::fromXContent, emptySet());
769+
}
770+
771+
/**
772+
* Asynchronously calls the analyze API
773+
*
774+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-analyze.html">Analyze API on elastic.co</a>
775+
*
776+
* @param request the request
777+
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
778+
* @param listener the listener to be notified upon request completion
779+
*/
780+
public void analyzeAsync(AnalyzeRequest request, RequestOptions options,
781+
ActionListener<AnalyzeResponse> listener) {
782+
restHighLevelClient.performRequestAsyncAndParseEntity(request, RequestConverters::analyze, options,
783+
AnalyzeResponse::fromXContent, listener, emptySet());
784+
}
755785
}

client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java

+13
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import org.elasticsearch.action.admin.cluster.snapshots.delete.DeleteSnapshotRequest;
4646
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
4747
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
48+
import org.elasticsearch.action.admin.indices.analyze.AnalyzeRequest;
4849
import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest;
4950
import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
5051
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
@@ -1019,6 +1020,18 @@ static Request getTemplates(GetIndexTemplatesRequest getIndexTemplatesRequest) t
10191020
return request;
10201021
}
10211022

1023+
static Request analyze(AnalyzeRequest request) throws IOException {
1024+
EndpointBuilder builder = new EndpointBuilder();
1025+
String index = request.index();
1026+
if (index != null) {
1027+
builder.addPathPart(index);
1028+
}
1029+
builder.addPathPartAsIs("_analyze");
1030+
Request req = new Request(HttpGet.METHOD_NAME, builder.build());
1031+
req.setEntity(createEntity(request, REQUEST_BODY_CONTENT_TYPE));
1032+
return req;
1033+
}
1034+
10221035
static Request getScript(GetStoredScriptRequest getStoredScriptRequest) {
10231036
String endpoint = new EndpointBuilder().addPathPartAsIs("_scripts").addPathPart(getStoredScriptRequest.id()).build();
10241037
Request request = new Request(HttpGet.METHOD_NAME, endpoint);

client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java

+18
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions;
3030
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse;
3131
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
32+
import org.elasticsearch.action.admin.indices.analyze.AnalyzeRequest;
33+
import org.elasticsearch.action.admin.indices.analyze.AnalyzeResponse;
3234
import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest;
3335
import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheResponse;
3436
import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
@@ -1278,4 +1280,20 @@ public void testGetIndexTemplate() throws Exception {
12781280
new GetIndexTemplatesRequest().names("the-template-*"), client.indices()::getTemplate, client.indices()::getTemplateAsync));
12791281
assertThat(notFound.status(), equalTo(RestStatus.NOT_FOUND));
12801282
}
1283+
1284+
public void testAnalyze() throws Exception {
1285+
1286+
RestHighLevelClient client = highLevelClient();
1287+
1288+
AnalyzeRequest noindexRequest = new AnalyzeRequest().text("One two three").analyzer("english");
1289+
AnalyzeResponse noindexResponse = execute(noindexRequest, client.indices()::analyze, client.indices()::analyzeAsync);
1290+
1291+
assertThat(noindexResponse.getTokens(), hasSize(3));
1292+
1293+
AnalyzeRequest detailsRequest = new AnalyzeRequest().text("One two three").analyzer("english").explain(true);
1294+
AnalyzeResponse detailsResponse = execute(detailsRequest, client.indices()::analyze, client.indices()::analyzeAsync);
1295+
1296+
assertNotNull(detailsResponse.detail());
1297+
1298+
}
12811299
}

client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java

+17
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
4848
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions;
4949
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
50+
import org.elasticsearch.action.admin.indices.analyze.AnalyzeRequest;
5051
import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest;
5152
import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
5253
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
@@ -2239,6 +2240,22 @@ public void testGetTemplateRequest() throws Exception {
22392240
assertThat(request.getEntity(), nullValue());
22402241
}
22412242

2243+
public void testAnalyzeRequest() throws Exception {
2244+
AnalyzeRequest indexAnalyzeRequest = new AnalyzeRequest()
2245+
.text("Here is some text")
2246+
.index("test_index")
2247+
.analyzer("test_analyzer");
2248+
2249+
Request request = RequestConverters.analyze(indexAnalyzeRequest);
2250+
assertThat(request.getEndpoint(), equalTo("/test_index/_analyze"));
2251+
assertToXContentBody(indexAnalyzeRequest, request.getEntity());
2252+
2253+
AnalyzeRequest analyzeRequest = new AnalyzeRequest()
2254+
.text("more text")
2255+
.analyzer("test_analyzer");
2256+
assertThat(RequestConverters.analyze(analyzeRequest).getEndpoint(), equalTo("/_analyze"));
2257+
}
2258+
22422259
public void testGetScriptRequest() {
22432260
GetStoredScriptRequest getStoredScriptRequest = new GetStoredScriptRequest("x-script");
22442261
Map<String, String> expectedParams = new HashMap<>();

client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java

+126
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@
2727
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions;
2828
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse;
2929
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
30+
import org.elasticsearch.action.admin.indices.analyze.AnalyzeRequest;
31+
import org.elasticsearch.action.admin.indices.analyze.AnalyzeResponse;
32+
import org.elasticsearch.action.admin.indices.analyze.DetailAnalyzeResponse;
3033
import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest;
3134
import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheResponse;
3235
import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
@@ -2317,4 +2320,127 @@ public void onFailure(Exception e) {
23172320

23182321
assertTrue(latch.await(30L, TimeUnit.SECONDS));
23192322
}
2323+
2324+
public void testAnalyze() throws IOException, InterruptedException {
2325+
2326+
RestHighLevelClient client = highLevelClient();
2327+
2328+
{
2329+
// tag::analyze-builtin-request
2330+
AnalyzeRequest request = new AnalyzeRequest();
2331+
request.text("Some text to analyze", "Some more text to analyze"); // <1>
2332+
request.analyzer("english"); // <2>
2333+
// end::analyze-builtin-request
2334+
}
2335+
2336+
{
2337+
// tag::analyze-custom-request
2338+
AnalyzeRequest request = new AnalyzeRequest();
2339+
request.text("<b>Some text to analyze</b>");
2340+
request.addCharFilter("html_strip"); // <1>
2341+
request.tokenizer("standard"); // <2>
2342+
request.addTokenFilter("lowercase"); // <3>
2343+
2344+
Map<String, Object> stopFilter = new HashMap<>();
2345+
stopFilter.put("type", "stop");
2346+
stopFilter.put("stopwords", new String[]{ "to" }); // <4>
2347+
request.addTokenFilter(stopFilter); // <5>
2348+
// end::analyze-custom-request
2349+
}
2350+
2351+
{
2352+
// tag::analyze-custom-normalizer-request
2353+
AnalyzeRequest request = new AnalyzeRequest();
2354+
request.text("<b>BaR</b>");
2355+
request.addTokenFilter("lowercase");
2356+
// end::analyze-custom-normalizer-request
2357+
2358+
// tag::analyze-request-explain
2359+
request.explain(true); // <1>
2360+
request.attributes("keyword", "type"); // <2>
2361+
// end::analyze-request-explain
2362+
2363+
// tag::analyze-request-sync
2364+
AnalyzeResponse response = client.indices().analyze(request, RequestOptions.DEFAULT);
2365+
// end::analyze-request-sync
2366+
2367+
// tag::analyze-response-tokens
2368+
List<AnalyzeResponse.AnalyzeToken> tokens = response.getTokens(); // <1>
2369+
// end::analyze-response-tokens
2370+
// tag::analyze-response-detail
2371+
DetailAnalyzeResponse detail = response.detail(); // <1>
2372+
// end::analyze-response-detail
2373+
2374+
assertNull(tokens);
2375+
assertNotNull(detail.tokenizer());
2376+
}
2377+
2378+
CreateIndexRequest req = new CreateIndexRequest("my_index");
2379+
CreateIndexResponse resp = client.indices().create(req, RequestOptions.DEFAULT);
2380+
assertTrue(resp.isAcknowledged());
2381+
2382+
PutMappingRequest pmReq = new PutMappingRequest()
2383+
.indices("my_index")
2384+
.type("_doc")
2385+
.source("my_field", "type=text,analyzer=english");
2386+
PutMappingResponse pmResp = client.indices().putMapping(pmReq, RequestOptions.DEFAULT);
2387+
assertTrue(pmResp.isAcknowledged());
2388+
2389+
{
2390+
// tag::analyze-index-request
2391+
AnalyzeRequest request = new AnalyzeRequest();
2392+
request.index("my_index"); // <1>
2393+
request.analyzer("my_analyzer"); // <2>
2394+
request.text("some text to analyze");
2395+
// end::analyze-index-request
2396+
2397+
// tag::analyze-execute-listener
2398+
ActionListener<AnalyzeResponse> listener = new ActionListener<AnalyzeResponse>() {
2399+
@Override
2400+
public void onResponse(AnalyzeResponse analyzeTokens) {
2401+
2402+
}
2403+
2404+
@Override
2405+
public void onFailure(Exception e) {
2406+
2407+
}
2408+
};
2409+
// end::analyze-execute-listener
2410+
2411+
// use a built-in analyzer in the test
2412+
request = new AnalyzeRequest();
2413+
request.index("my_index");
2414+
request.field("my_field");
2415+
request.text("some text to analyze");
2416+
// Use a blocking listener in the test
2417+
final CountDownLatch latch = new CountDownLatch(1);
2418+
listener = new LatchedActionListener<>(listener, latch);
2419+
2420+
// tag::analyze-request-async
2421+
client.indices().analyzeAsync(request, RequestOptions.DEFAULT, listener);
2422+
// end::analyze-request-async
2423+
2424+
assertTrue(latch.await(30L, TimeUnit.SECONDS));
2425+
}
2426+
2427+
{
2428+
// tag::analyze-index-normalizer-request
2429+
AnalyzeRequest request = new AnalyzeRequest();
2430+
request.index("my_index"); // <1>
2431+
request.normalizer("my_normalizer"); // <2>
2432+
request.text("some text to analyze");
2433+
// end::analyze-index-normalizer-request
2434+
}
2435+
2436+
{
2437+
// tag::analyze-field-request
2438+
AnalyzeRequest request = new AnalyzeRequest();
2439+
request.index("my_index");
2440+
request.field("my_field");
2441+
request.text("some text to analyze");
2442+
// end::analyze-field-request
2443+
}
2444+
2445+
}
23202446
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
[[java-rest-high-analyze]]
2+
=== Analyze API
3+
4+
[[java-rest-high-analyze-request]]
5+
==== Analyze Request
6+
7+
An `AnalyzeRequest` contains the text to analyze, and one of several options to
8+
specify how the analysis should be performed.
9+
10+
The simplest version uses a built-in analyzer:
11+
12+
["source","java",subs="attributes,callouts,macros"]
13+
---------------------------------------------------
14+
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[analyze-builtin-request]
15+
---------------------------------------------------
16+
<1> The text to include. Multiple strings are treated as a multi-valued field
17+
<2> A built-in analyzer
18+
19+
You can configure a custom analyzer:
20+
["source","java",subs="attributes,callouts,macros"]
21+
---------------------------------------------------
22+
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[analyze-custom-request]
23+
---------------------------------------------------
24+
<1> Configure char filters
25+
<2> Configure the tokenizer
26+
<3> Add a built-in tokenfilter
27+
<4> Configuration for a custom tokenfilter
28+
<5> Add the custom tokenfilter
29+
30+
You can also build a custom normalizer, by including only charfilters and
31+
tokenfilters:
32+
["source","java",subs="attributes,callouts,macros"]
33+
---------------------------------------------------
34+
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[analyze-custom-normalizer-request]
35+
---------------------------------------------------
36+
37+
You can analyze text using an analyzer defined in an existing index:
38+
["source","java",subs="attributes,callouts,macros"]
39+
---------------------------------------------------
40+
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[analyze-index-request]
41+
---------------------------------------------------
42+
<1> The index containing the mappings
43+
<2> The analyzer defined on this index to use
44+
45+
Or you can use a normalizer:
46+
["source","java",subs="attributes,callouts,macros"]
47+
---------------------------------------------------
48+
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[analyze-index-normalizer-request]
49+
---------------------------------------------------
50+
<1> The index containing the mappings
51+
<2> The normalizer defined on this index to use
52+
53+
You can analyze text using the mappings for a particular field in an index:
54+
["source","java",subs="attributes,callouts,macros"]
55+
---------------------------------------------------
56+
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[analyze-field-request]
57+
---------------------------------------------------
58+
59+
==== Optional arguemnts
60+
The following arguments can also optionally be provided:
61+
62+
["source","java",subs="attributes,callouts,macros"]
63+
---------------------------------------------------
64+
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[analyze-request-explain]
65+
---------------------------------------------------
66+
<1> Setting `explain` to true will add further details to the response
67+
<2> Setting `attributes` allows you to return only token attributes that you are
68+
interested in
69+
70+
[[java-rest-high-analyze-sync]]
71+
==== Synchronous Execution
72+
73+
["source","java",subs="attributes,callouts,macros"]
74+
---------------------------------------------------
75+
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[analyze-request-sync]
76+
---------------------------------------------------
77+
78+
[[java-rest-high-analyze-async]]
79+
==== Asynchronous Execution
80+
81+
The asynchronous execution of an analyze request requires both the `AnalyzeRequest`
82+
instance and an `ActionListener` instance to be passed to the asyncronous method:
83+
84+
["source","java",subs="attributes,callouts,macros"]
85+
---------------------------------------------------
86+
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[analyze-request-async]
87+
---------------------------------------------------
88+
89+
The asynchronous method does not block and returns immediately. Once it is
90+
completed the `ActionListener` is called back using the `onResponse` method if the
91+
execution successfully completed or using the `onFailure` method if it failed.
92+
93+
A typical listener for `AnalyzeResponse` looks like:
94+
95+
["source","java",subs="attributes,callouts,macros"]
96+
---------------------------------------------------
97+
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[analyze-execute-listener]
98+
---------------------------------------------------
99+
100+
[[java-rest-high-analyze-response]]
101+
==== Analyze Response
102+
103+
The returned `AnalyzeResponse` allows you to retrieve details of the analysis as
104+
follows:
105+
["source","java",subs="attributes,callouts,macros"]
106+
---------------------------------------------------
107+
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[analyze-response-tokens]
108+
---------------------------------------------------
109+
<1> `AnalyzeToken` holds information about the individual tokens produced by analysis
110+
111+
If `explain` was set to `true`, then information is instead returned from the `detail()`
112+
method:
113+
114+
["source","java",subs="attributes,callouts,macros"]
115+
---------------------------------------------------
116+
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[analyze-response-detail]
117+
---------------------------------------------------
118+
<1> `DetailAnalyzeResponse` holds more detailed information about tokens produced by
119+
the various substeps in the analysis chain.

docs/java-rest/high-level/supported-apis.asciidoc

+1
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ Alias Management::
8888
* <<java-rest-high-exists-alias>>
8989
* <<java-rest-high-get-alias>>
9090

91+
include::indices/analyze.asciidoc[]
9192
include::indices/create_index.asciidoc[]
9293
include::indices/delete_index.asciidoc[]
9394
include::indices/indices_exists.asciidoc[]

0 commit comments

Comments
 (0)