mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Search] Server strategy example (#71679)
* Server strategy example * Add tsconfig Renamed is_partial to isPartial Added isPartial and isRunning to OSS response type * Docs + remove unused sample code * Fix test naming of arguments * ts * ts fix * Add filters and query input selector * Update examples/search_examples/public/components/app.tsx Co-authored-by: Lukas Olson <olson.lukas@gmail.com> * Use new service * exapmle plugin ts * unsubscribe + use timefilter * typo * docs * Add comments and use agg config * Added agg configs Added field selector Added a custom input param * Adding getEsQuery to query service (??) * Add server side example * docs * caps * list plugin in examples page * fix typo * Update examples/search_examples/public/application.tsx Co-authored-by: Lukas Olson <olson.lukas@gmail.com> * Update examples/search_examples/public/application.tsx Co-authored-by: Lukas Olson <olson.lukas@gmail.com> * Update examples/search_examples/public/components/app.tsx Co-authored-by: Lukas Olson <olson.lukas@gmail.com> * Update examples/search_examples/public/components/app.tsx Co-authored-by: Lukas Olson <olson.lukas@gmail.com> * Update examples/search_examples/public/components/app.tsx Co-authored-by: Lukas Olson <olson.lukas@gmail.com> * eslint Co-authored-by: Lukas Olson <olson.lukas@gmail.com> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
d78644229e
commit
506e9537bf
49 changed files with 1161 additions and 106 deletions
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IEsSearchResponse](./kibana-plugin-plugins-data-public.iessearchresponse.md) > [isPartial](./kibana-plugin-plugins-data-public.iessearchresponse.ispartial.md)
|
||||
|
||||
## IEsSearchResponse.isPartial property
|
||||
|
||||
Indicates whether the results returned are complete or partial
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
isPartial?: boolean;
|
||||
```
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IEsSearchResponse](./kibana-plugin-plugins-data-public.iessearchresponse.md) > [isRunning](./kibana-plugin-plugins-data-public.iessearchresponse.isrunning.md)
|
||||
|
||||
## IEsSearchResponse.isRunning property
|
||||
|
||||
Indicates whether async search is still in flight
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
isRunning?: boolean;
|
||||
```
|
|
@ -14,5 +14,7 @@ export interface IEsSearchResponse extends IKibanaSearchResponse
|
|||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [isPartial](./kibana-plugin-plugins-data-public.iessearchresponse.ispartial.md) | <code>boolean</code> | Indicates whether the results returned are complete or partial |
|
||||
| [isRunning](./kibana-plugin-plugins-data-public.iessearchresponse.isrunning.md) | <code>boolean</code> | Indicates whether async search is still in flight |
|
||||
| [rawResponse](./kibana-plugin-plugins-data-public.iessearchresponse.rawresponse.md) | <code>SearchResponse<any></code> | |
|
||||
|
||||
|
|
|
@ -7,5 +7,5 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare type ISearchGeneric = (request: IEsSearchRequest, options?: IStrategyOptions) => Observable<IEsSearchResponse>;
|
||||
export declare type ISearchGeneric = (request: IEsSearchRequest, options?: ISearchOptions) => Observable<IEsSearchResponse>;
|
||||
```
|
||||
|
|
|
@ -15,4 +15,5 @@ export interface ISearchOptions
|
|||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [signal](./kibana-plugin-plugins-data-public.isearchoptions.signal.md) | <code>AbortSignal</code> | |
|
||||
| [strategy](./kibana-plugin-plugins-data-public.isearchoptions.strategy.md) | <code>string</code> | |
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [ISearchOptions](./kibana-plugin-plugins-data-public.isearchoptions.md) > [strategy](./kibana-plugin-plugins-data-public.isearchoptions.strategy.md)
|
||||
|
||||
## ISearchOptions.strategy property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
strategy?: string;
|
||||
```
|
|
@ -35,7 +35,7 @@ export declare class SearchInterceptor
|
|||
|
||||
| Method | Modifiers | Description |
|
||||
| --- | --- | --- |
|
||||
| [runSearch(request, signal)](./kibana-plugin-plugins-data-public.searchinterceptor.runsearch.md) | | |
|
||||
| [runSearch(request, signal, strategy)](./kibana-plugin-plugins-data-public.searchinterceptor.runsearch.md) | | |
|
||||
| [search(request, options)](./kibana-plugin-plugins-data-public.searchinterceptor.search.md) | | Searches using the given <code>search</code> method. Overrides the <code>AbortSignal</code> with one that will abort either when <code>cancelPending</code> is called, when the request times out, or when the original <code>AbortSignal</code> is aborted. Updates the <code>pendingCount</code> when the request is started/finalized. |
|
||||
| [setupTimers(options)](./kibana-plugin-plugins-data-public.searchinterceptor.setuptimers.md) | | |
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
protected runSearch(request: IEsSearchRequest, signal: AbortSignal): Observable<IEsSearchResponse>;
|
||||
protected runSearch(request: IEsSearchRequest, signal: AbortSignal, strategy?: string): Observable<IEsSearchResponse>;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
@ -16,6 +16,7 @@ protected runSearch(request: IEsSearchRequest, signal: AbortSignal): Observable<
|
|||
| --- | --- | --- |
|
||||
| request | <code>IEsSearchRequest</code> | |
|
||||
| signal | <code>AbortSignal</code> | |
|
||||
| strategy | <code>string</code> | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [IEsSearchRequest](./kibana-plugin-plugins-data-server.iessearchrequest.md) > [indexType](./kibana-plugin-plugins-data-server.iessearchrequest.indextype.md)
|
||||
|
||||
## IEsSearchRequest.indexType property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
indexType?: string;
|
||||
```
|
|
@ -0,0 +1,19 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [IEsSearchRequest](./kibana-plugin-plugins-data-server.iessearchrequest.md)
|
||||
|
||||
## IEsSearchRequest interface
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface IEsSearchRequest extends IKibanaSearchRequest
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [indexType](./kibana-plugin-plugins-data-server.iessearchrequest.indextype.md) | <code>string</code> | |
|
||||
| [params](./kibana-plugin-plugins-data-server.iessearchrequest.params.md) | <code>ISearchRequestParams</code> | |
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [IEsSearchRequest](./kibana-plugin-plugins-data-server.iessearchrequest.md) > [params](./kibana-plugin-plugins-data-server.iessearchrequest.params.md)
|
||||
|
||||
## IEsSearchRequest.params property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
params?: ISearchRequestParams;
|
||||
```
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [IEsSearchResponse](./kibana-plugin-plugins-data-server.iessearchresponse.md) > [isPartial](./kibana-plugin-plugins-data-server.iessearchresponse.ispartial.md)
|
||||
|
||||
## IEsSearchResponse.isPartial property
|
||||
|
||||
Indicates whether the results returned are complete or partial
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
isPartial?: boolean;
|
||||
```
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [IEsSearchResponse](./kibana-plugin-plugins-data-server.iessearchresponse.md) > [isRunning](./kibana-plugin-plugins-data-server.iessearchresponse.isrunning.md)
|
||||
|
||||
## IEsSearchResponse.isRunning property
|
||||
|
||||
Indicates whether async search is still in flight
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
isRunning?: boolean;
|
||||
```
|
|
@ -0,0 +1,20 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [IEsSearchResponse](./kibana-plugin-plugins-data-server.iessearchresponse.md)
|
||||
|
||||
## IEsSearchResponse interface
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface IEsSearchResponse extends IKibanaSearchResponse
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [isPartial](./kibana-plugin-plugins-data-server.iessearchresponse.ispartial.md) | <code>boolean</code> | Indicates whether the results returned are complete or partial |
|
||||
| [isRunning](./kibana-plugin-plugins-data-server.iessearchresponse.isrunning.md) | <code>boolean</code> | Indicates whether async search is still in flight |
|
||||
| [rawResponse](./kibana-plugin-plugins-data-server.iessearchresponse.rawresponse.md) | <code>SearchResponse<any></code> | |
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [IEsSearchResponse](./kibana-plugin-plugins-data-server.iessearchresponse.md) > [rawResponse](./kibana-plugin-plugins-data-server.iessearchresponse.rawresponse.md)
|
||||
|
||||
## IEsSearchResponse.rawResponse property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
rawResponse: SearchResponse<any>;
|
||||
```
|
|
@ -36,6 +36,8 @@
|
|||
| [EsQueryConfig](./kibana-plugin-plugins-data-server.esqueryconfig.md) | |
|
||||
| [FieldFormatConfig](./kibana-plugin-plugins-data-server.fieldformatconfig.md) | |
|
||||
| [Filter](./kibana-plugin-plugins-data-server.filter.md) | |
|
||||
| [IEsSearchRequest](./kibana-plugin-plugins-data-server.iessearchrequest.md) | |
|
||||
| [IEsSearchResponse](./kibana-plugin-plugins-data-server.iessearchresponse.md) | |
|
||||
| [IFieldSubType](./kibana-plugin-plugins-data-server.ifieldsubtype.md) | |
|
||||
| [IFieldType](./kibana-plugin-plugins-data-server.ifieldtype.md) | |
|
||||
| [IIndexPattern](./kibana-plugin-plugins-data-server.iindexpattern.md) | |
|
||||
|
|
9
examples/search_examples/README.md
Normal file
9
examples/search_examples/README.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
# search_examples
|
||||
|
||||
> An awesome Kibana plugin
|
||||
|
||||
---
|
||||
|
||||
## Development
|
||||
|
||||
See the [kibana contributing guide](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md) for instructions setting up your development environment.
|
32
examples/search_examples/common/index.ts
Normal file
32
examples/search_examples/common/index.ts
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { IEsSearchResponse, IEsSearchRequest } from '../../../src/plugins/data/common';
|
||||
|
||||
export const PLUGIN_ID = 'searchExamples';
|
||||
export const PLUGIN_NAME = 'Search Examples';
|
||||
|
||||
export interface IMyStrategyRequest extends IEsSearchRequest {
|
||||
get_cool: boolean;
|
||||
}
|
||||
export interface IMyStrategyResponse extends IEsSearchResponse {
|
||||
cool: string;
|
||||
}
|
||||
|
||||
export const SERVER_SEARCH_ROUTE_PATH = '/api/examples/search';
|
9
examples/search_examples/kibana.json
Normal file
9
examples/search_examples/kibana.json
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"id": "searchExamples",
|
||||
"version": "8.0.0",
|
||||
"server": true,
|
||||
"ui": true,
|
||||
"requiredPlugins": ["navigation", "data", "developerExamples"],
|
||||
"optionalPlugins": [],
|
||||
"requiredBundles": []
|
||||
}
|
44
examples/search_examples/public/application.tsx
Normal file
44
examples/search_examples/public/application.tsx
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { AppMountParameters, CoreStart } from '../../../src/core/public';
|
||||
import { AppPluginStartDependencies } from './types';
|
||||
import { SearchExamplesApp } from './components/app';
|
||||
|
||||
export const renderApp = (
|
||||
{ notifications, savedObjects, http }: CoreStart,
|
||||
{ navigation, data }: AppPluginStartDependencies,
|
||||
{ appBasePath, element }: AppMountParameters
|
||||
) => {
|
||||
ReactDOM.render(
|
||||
<SearchExamplesApp
|
||||
basename={appBasePath}
|
||||
notifications={notifications}
|
||||
savedObjectsClient={savedObjects.client}
|
||||
navigation={navigation}
|
||||
data={data}
|
||||
http={http}
|
||||
/>,
|
||||
element
|
||||
);
|
||||
|
||||
return () => ReactDOM.unmountComponentAtNode(element);
|
||||
};
|
341
examples/search_examples/public/components/app.tsx
Normal file
341
examples/search_examples/public/components/app.tsx
Normal file
|
@ -0,0 +1,341 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage, I18nProvider } from '@kbn/i18n/react';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
|
||||
import {
|
||||
EuiButton,
|
||||
EuiPage,
|
||||
EuiPageBody,
|
||||
EuiPageContent,
|
||||
EuiPageContentBody,
|
||||
EuiPageHeader,
|
||||
EuiTitle,
|
||||
EuiText,
|
||||
EuiFlexGrid,
|
||||
EuiFlexItem,
|
||||
EuiCheckbox,
|
||||
EuiSpacer,
|
||||
EuiCode,
|
||||
EuiComboBox,
|
||||
EuiFormLabel,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { CoreStart } from '../../../../src/core/public';
|
||||
import { mountReactNode } from '../../../../src/core/public/utils';
|
||||
import { NavigationPublicPluginStart } from '../../../../src/plugins/navigation/public';
|
||||
|
||||
import {
|
||||
PLUGIN_ID,
|
||||
PLUGIN_NAME,
|
||||
IMyStrategyRequest,
|
||||
IMyStrategyResponse,
|
||||
SERVER_SEARCH_ROUTE_PATH,
|
||||
} from '../../common';
|
||||
|
||||
import {
|
||||
DataPublicPluginStart,
|
||||
IndexPatternSelect,
|
||||
IndexPattern,
|
||||
IndexPatternField,
|
||||
} from '../../../../src/plugins/data/public';
|
||||
|
||||
interface SearchExamplesAppDeps {
|
||||
basename: string;
|
||||
notifications: CoreStart['notifications'];
|
||||
http: CoreStart['http'];
|
||||
savedObjectsClient: CoreStart['savedObjects']['client'];
|
||||
navigation: NavigationPublicPluginStart;
|
||||
data: DataPublicPluginStart;
|
||||
}
|
||||
|
||||
function formatFieldToComboBox(field?: IndexPatternField | null) {
|
||||
if (!field) return [];
|
||||
return formatFieldsToComboBox([field]);
|
||||
}
|
||||
|
||||
function formatFieldsToComboBox(fields?: IndexPatternField[]) {
|
||||
if (!fields) return [];
|
||||
|
||||
return fields?.map((field) => {
|
||||
return {
|
||||
label: field.displayName || field.name,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export const SearchExamplesApp = ({
|
||||
http,
|
||||
basename,
|
||||
notifications,
|
||||
savedObjectsClient,
|
||||
navigation,
|
||||
data,
|
||||
}: SearchExamplesAppDeps) => {
|
||||
const [getCool, setGetCool] = useState<boolean>(false);
|
||||
const [timeTook, setTimeTook] = useState<number | undefined>();
|
||||
const [indexPattern, setIndexPattern] = useState<IndexPattern | null>();
|
||||
const [numericFields, setNumericFields] = useState<IndexPatternField[]>();
|
||||
const [selectedField, setSelectedField] = useState<IndexPatternField | null | undefined>();
|
||||
|
||||
// Fetch the default index pattern using the `data.indexPatterns` service, as the component is mounted.
|
||||
useEffect(() => {
|
||||
const setDefaultIndexPattern = async () => {
|
||||
const defaultIndexPattern = await data.indexPatterns.getDefault();
|
||||
setIndexPattern(defaultIndexPattern);
|
||||
};
|
||||
|
||||
setDefaultIndexPattern();
|
||||
}, [data]);
|
||||
|
||||
// Update the fields list every time the index pattern is modified.
|
||||
useEffect(() => {
|
||||
const fields = indexPattern?.fields.filter(
|
||||
(field) => field.type === 'number' && field.aggregatable
|
||||
);
|
||||
setNumericFields(fields);
|
||||
setSelectedField(fields?.length ? fields[0] : null);
|
||||
}, [indexPattern]);
|
||||
|
||||
const doAsyncSearch = async (strategy?: string) => {
|
||||
if (!indexPattern || !selectedField) return;
|
||||
|
||||
// Constuct the query portion of the search request
|
||||
const query = data.query.getEsQuery(indexPattern);
|
||||
|
||||
// Constuct the aggregations portion of the search request by using the `data.search.aggs` service.
|
||||
const aggs = [{ type: 'avg', params: { field: selectedField.name } }];
|
||||
const aggsDsl = data.search.aggs.createAggConfigs(indexPattern, aggs).toDsl();
|
||||
|
||||
const request = {
|
||||
params: {
|
||||
index: indexPattern.title,
|
||||
body: {
|
||||
aggs: aggsDsl,
|
||||
query,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
if (strategy) {
|
||||
// Add a custom request parameter to be consumed by `MyStrategy`.
|
||||
(request as IMyStrategyRequest).get_cool = getCool;
|
||||
}
|
||||
|
||||
// Submit the search request using the `data.search` service.
|
||||
const searchSubscription$ = data.search
|
||||
.search(request, {
|
||||
strategy,
|
||||
})
|
||||
.subscribe({
|
||||
next: (response) => {
|
||||
if (!response.isPartial && !response.isRunning) {
|
||||
setTimeTook(response.rawResponse.took);
|
||||
const avgResult: number | undefined = response.rawResponse.aggregations
|
||||
? response.rawResponse.aggregations[1].value
|
||||
: undefined;
|
||||
const message = (
|
||||
<EuiText>
|
||||
Searched {response.rawResponse.hits.total} documents. <br />
|
||||
The average of {selectedField.name} is {avgResult ? Math.floor(avgResult) : 0}.
|
||||
<br />
|
||||
Is it Cool? {String((response as IMyStrategyResponse).cool)}
|
||||
</EuiText>
|
||||
);
|
||||
notifications.toasts.addSuccess({
|
||||
title: 'Query result',
|
||||
text: mountReactNode(message),
|
||||
});
|
||||
searchSubscription$.unsubscribe();
|
||||
} else if (response.isPartial && !response.isRunning) {
|
||||
// TODO: Make response error status clearer
|
||||
notifications.toasts.addWarning('An error has occurred');
|
||||
searchSubscription$.unsubscribe();
|
||||
}
|
||||
},
|
||||
error: () => {
|
||||
notifications.toasts.addDanger('Failed to run search');
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const onClickHandler = () => {
|
||||
doAsyncSearch();
|
||||
};
|
||||
|
||||
const onMyStrategyClickHandler = () => {
|
||||
doAsyncSearch('myStrategy');
|
||||
};
|
||||
|
||||
const onServerClickHandler = async () => {
|
||||
if (!indexPattern || !selectedField) return;
|
||||
try {
|
||||
const response = await http.get(SERVER_SEARCH_ROUTE_PATH, {
|
||||
query: {
|
||||
index: indexPattern.title,
|
||||
field: selectedField.name,
|
||||
},
|
||||
});
|
||||
|
||||
notifications.toasts.addSuccess(`Server returned ${JSON.stringify(response)}`);
|
||||
} catch (e) {
|
||||
notifications.toasts.addDanger('Failed to run search');
|
||||
}
|
||||
};
|
||||
|
||||
if (!indexPattern) return null;
|
||||
|
||||
return (
|
||||
<Router basename={basename}>
|
||||
<I18nProvider>
|
||||
<>
|
||||
<navigation.ui.TopNavMenu
|
||||
appName={PLUGIN_ID}
|
||||
showSearchBar={true}
|
||||
useDefaultBehaviors={true}
|
||||
indexPatterns={indexPattern ? [indexPattern] : undefined}
|
||||
/>
|
||||
<EuiPage restrictWidth="1000px">
|
||||
<EuiPageBody>
|
||||
<EuiPageHeader>
|
||||
<EuiTitle size="l">
|
||||
<h1>
|
||||
<FormattedMessage
|
||||
id="searchExamples.helloWorldText"
|
||||
defaultMessage="{name}"
|
||||
values={{ name: PLUGIN_NAME }}
|
||||
/>
|
||||
</h1>
|
||||
</EuiTitle>
|
||||
</EuiPageHeader>
|
||||
<EuiPageContent>
|
||||
<EuiPageContentBody>
|
||||
<EuiText>
|
||||
<EuiFlexGrid columns={1}>
|
||||
<EuiFlexItem>
|
||||
<EuiFormLabel>Index Pattern</EuiFormLabel>
|
||||
<IndexPatternSelect
|
||||
savedObjectsClient={savedObjectsClient}
|
||||
placeholder={i18n.translate(
|
||||
'backgroundSessionExample.selectIndexPatternPlaceholder',
|
||||
{
|
||||
defaultMessage: 'Select index pattern',
|
||||
}
|
||||
)}
|
||||
indexPatternId={indexPattern?.id || ''}
|
||||
onChange={async (newIndexPatternId: any) => {
|
||||
const newIndexPattern = await data.indexPatterns.get(newIndexPatternId);
|
||||
setIndexPattern(newIndexPattern);
|
||||
}}
|
||||
isClearable={false}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiFormLabel>Numeric Fields</EuiFormLabel>
|
||||
<EuiComboBox
|
||||
options={formatFieldsToComboBox(numericFields)}
|
||||
selectedOptions={formatFieldToComboBox(selectedField)}
|
||||
singleSelection={true}
|
||||
onChange={(option) => {
|
||||
const field = indexPattern.getFieldByName(option[0].label);
|
||||
setSelectedField(field || null);
|
||||
}}
|
||||
sortMatchesBy="startsWith"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGrid>
|
||||
</EuiText>
|
||||
<EuiText>
|
||||
<FormattedMessage
|
||||
id="searchExamples.timestampText"
|
||||
defaultMessage="Last query took: {time} ms"
|
||||
values={{ time: timeTook || 'Unknown' }}
|
||||
/>
|
||||
</EuiText>
|
||||
<EuiSpacer />
|
||||
<EuiTitle size="s">
|
||||
<h3>
|
||||
Searching Elasticsearch using <EuiCode>data.search</EuiCode>
|
||||
</h3>
|
||||
</EuiTitle>
|
||||
<EuiText>
|
||||
If you want to fetch data from Elasticsearch, you can use the different services
|
||||
provided by the <EuiCode>data</EuiCode> plugin. These help you get the index
|
||||
pattern and search bar configuration, format them into a DSL query and send it
|
||||
to Elasticsearch.
|
||||
<EuiSpacer />
|
||||
<EuiButton type="primary" size="s" onClick={onClickHandler}>
|
||||
<FormattedMessage id="searchExamples.buttonText" defaultMessage="Get data" />
|
||||
</EuiButton>
|
||||
</EuiText>
|
||||
<EuiSpacer />
|
||||
<EuiTitle size="s">
|
||||
<h3>Writing a custom search strategy</h3>
|
||||
</EuiTitle>
|
||||
<EuiText>
|
||||
If you want to do some pre or post processing on the server, you might want to
|
||||
create a custom search strategy. This example uses such a strategy, passing in
|
||||
custom input and receiving custom output back.
|
||||
<EuiSpacer />
|
||||
<EuiCheckbox
|
||||
id="GetCool"
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="searchExamples.getCoolCheckbox"
|
||||
defaultMessage="Get cool parameter?"
|
||||
/>
|
||||
}
|
||||
checked={getCool}
|
||||
onChange={(event) => setGetCool(event.target.checked)}
|
||||
/>
|
||||
<EuiButton type="primary" size="s" onClick={onMyStrategyClickHandler}>
|
||||
<FormattedMessage
|
||||
id="searchExamples.myStrategyButtonText"
|
||||
defaultMessage="Get data via My Strategy"
|
||||
/>
|
||||
</EuiButton>
|
||||
</EuiText>
|
||||
<EuiSpacer />
|
||||
<EuiTitle size="s">
|
||||
<h3>Using search on the server</h3>
|
||||
</EuiTitle>
|
||||
<EuiText>
|
||||
You can also run your search request from the server, without registering a
|
||||
search strategy. This request does not take the configuration of{' '}
|
||||
<EuiCode>TopNavMenu</EuiCode> into account, but you could pass those down to the
|
||||
server as well.
|
||||
<EuiButton type="primary" size="s" onClick={onServerClickHandler}>
|
||||
<FormattedMessage
|
||||
id="searchExamples.myServerButtonText"
|
||||
defaultMessage="Get data on the server"
|
||||
/>
|
||||
</EuiButton>
|
||||
</EuiText>
|
||||
</EuiPageContentBody>
|
||||
</EuiPageContent>
|
||||
</EuiPageBody>
|
||||
</EuiPage>
|
||||
</>
|
||||
</I18nProvider>
|
||||
</Router>
|
||||
);
|
||||
};
|
0
examples/search_examples/public/index.scss
Normal file
0
examples/search_examples/public/index.scss
Normal file
29
examples/search_examples/public/index.ts
Normal file
29
examples/search_examples/public/index.ts
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import './index.scss';
|
||||
|
||||
import { SearchExamplesPlugin } from './plugin';
|
||||
|
||||
// This exports static code and TypeScript types,
|
||||
// as well as, Kibana Platform `plugin()` initializer.
|
||||
export function plugin() {
|
||||
return new SearchExamplesPlugin();
|
||||
}
|
||||
export { SearchExamplesPluginSetup, SearchExamplesPluginStart } from './types';
|
76
examples/search_examples/public/plugin.ts
Normal file
76
examples/search_examples/public/plugin.ts
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
AppMountParameters,
|
||||
CoreSetup,
|
||||
CoreStart,
|
||||
Plugin,
|
||||
AppNavLinkStatus,
|
||||
} from '../../../src/core/public';
|
||||
import {
|
||||
SearchExamplesPluginSetup,
|
||||
SearchExamplesPluginStart,
|
||||
AppPluginSetupDependencies,
|
||||
AppPluginStartDependencies,
|
||||
} from './types';
|
||||
import { PLUGIN_NAME } from '../common';
|
||||
|
||||
export class SearchExamplesPlugin
|
||||
implements
|
||||
Plugin<
|
||||
SearchExamplesPluginSetup,
|
||||
SearchExamplesPluginStart,
|
||||
AppPluginSetupDependencies,
|
||||
AppPluginStartDependencies
|
||||
> {
|
||||
public setup(
|
||||
core: CoreSetup<AppPluginStartDependencies>,
|
||||
{ developerExamples }: AppPluginSetupDependencies
|
||||
): SearchExamplesPluginSetup {
|
||||
// Register an application into the side navigation menu
|
||||
core.application.register({
|
||||
id: 'searchExamples',
|
||||
title: PLUGIN_NAME,
|
||||
navLinkStatus: AppNavLinkStatus.hidden,
|
||||
async mount(params: AppMountParameters) {
|
||||
// Load application bundle
|
||||
const { renderApp } = await import('./application');
|
||||
// Get start services as specified in kibana.json
|
||||
const [coreStart, depsStart] = await core.getStartServices();
|
||||
// Render the application
|
||||
return renderApp(coreStart, depsStart, params);
|
||||
},
|
||||
});
|
||||
|
||||
developerExamples.register({
|
||||
appId: 'searchExamples',
|
||||
title: 'Search Examples',
|
||||
description: `Search Examples`,
|
||||
});
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
public start(core: CoreStart): SearchExamplesPluginStart {
|
||||
return {};
|
||||
}
|
||||
|
||||
public stop() {}
|
||||
}
|
36
examples/search_examples/public/types.ts
Normal file
36
examples/search_examples/public/types.ts
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { NavigationPublicPluginStart } from '../../../src/plugins/navigation/public';
|
||||
import { DataPublicPluginStart } from '../../../src/plugins/data/public';
|
||||
import { DeveloperExamplesSetup } from '../../developer_examples/public';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface SearchExamplesPluginSetup {}
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface SearchExamplesPluginStart {}
|
||||
|
||||
export interface AppPluginSetupDependencies {
|
||||
developerExamples: DeveloperExamplesSetup;
|
||||
}
|
||||
|
||||
export interface AppPluginStartDependencies {
|
||||
navigation: NavigationPublicPluginStart;
|
||||
data: DataPublicPluginStart;
|
||||
}
|
27
examples/search_examples/server/index.ts
Normal file
27
examples/search_examples/server/index.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { PluginInitializerContext } from '../../../src/core/server';
|
||||
import { SearchExamplesPlugin } from './plugin';
|
||||
|
||||
export function plugin(initializerContext: PluginInitializerContext) {
|
||||
return new SearchExamplesPlugin(initializerContext);
|
||||
}
|
||||
|
||||
export { SearchExamplesPluginSetup, SearchExamplesPluginStart } from './types';
|
40
examples/search_examples/server/my_strategy.ts
Normal file
40
examples/search_examples/server/my_strategy.ts
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { ISearchStrategy, PluginStart } from '../../../src/plugins/data/server';
|
||||
import { IMyStrategyResponse, IMyStrategyRequest } from '../common';
|
||||
|
||||
export const mySearchStrategyProvider = (data: PluginStart): ISearchStrategy => {
|
||||
const es = data.search.getSearchStrategy('es');
|
||||
return {
|
||||
search: async (context, request, options): Promise<IMyStrategyResponse> => {
|
||||
request.debug = true;
|
||||
const esSearchRes = await es.search(context, request, options);
|
||||
return {
|
||||
...esSearchRes,
|
||||
cool: (request as IMyStrategyRequest).get_cool ? 'YES' : 'NOPE',
|
||||
};
|
||||
},
|
||||
cancel: async (context, id) => {
|
||||
if (es.cancel) {
|
||||
es.cancel(context, id);
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
73
examples/search_examples/server/plugin.ts
Normal file
73
examples/search_examples/server/plugin.ts
Normal file
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
PluginInitializerContext,
|
||||
CoreSetup,
|
||||
CoreStart,
|
||||
Plugin,
|
||||
Logger,
|
||||
} from '../../../src/core/server';
|
||||
|
||||
import {
|
||||
SearchExamplesPluginSetup,
|
||||
SearchExamplesPluginStart,
|
||||
SearchExamplesPluginSetupDeps,
|
||||
SearchExamplesPluginStartDeps,
|
||||
} from './types';
|
||||
import { mySearchStrategyProvider } from './my_strategy';
|
||||
import { registerRoutes } from './routes';
|
||||
|
||||
export class SearchExamplesPlugin
|
||||
implements
|
||||
Plugin<
|
||||
SearchExamplesPluginSetup,
|
||||
SearchExamplesPluginStart,
|
||||
SearchExamplesPluginSetupDeps,
|
||||
SearchExamplesPluginStartDeps
|
||||
> {
|
||||
private readonly logger: Logger;
|
||||
|
||||
constructor(initializerContext: PluginInitializerContext) {
|
||||
this.logger = initializerContext.logger.get();
|
||||
}
|
||||
|
||||
public setup(
|
||||
core: CoreSetup<SearchExamplesPluginStartDeps>,
|
||||
deps: SearchExamplesPluginSetupDeps
|
||||
) {
|
||||
this.logger.debug('search_examples: Setup');
|
||||
const router = core.http.createRouter();
|
||||
|
||||
core.getStartServices().then(([_, depsStart]) => {
|
||||
const myStrategy = mySearchStrategyProvider(depsStart.data);
|
||||
deps.data.search.registerSearchStrategy('myStrategy', myStrategy);
|
||||
registerRoutes(router, depsStart.data);
|
||||
});
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
public start(core: CoreStart) {
|
||||
this.logger.debug('search_examples: Started');
|
||||
return {};
|
||||
}
|
||||
|
||||
public stop() {}
|
||||
}
|
19
examples/search_examples/server/routes/index.ts
Normal file
19
examples/search_examples/server/routes/index.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
export { registerRoutes } from './register_routes';
|
26
examples/search_examples/server/routes/register_routes.ts
Normal file
26
examples/search_examples/server/routes/register_routes.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { IRouter } from 'kibana/server';
|
||||
import { PluginStart as DataPluginStart } from 'src/plugins/data/server';
|
||||
import { registerServerSearchRoute } from './server_search_route';
|
||||
|
||||
export function registerRoutes(router: IRouter, data: DataPluginStart) {
|
||||
registerServerSearchRoute(router, data);
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { PluginStart as DataPluginStart, IEsSearchRequest } from 'src/plugins/data/server';
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { IEsSearchResponse } from 'src/plugins/data/common';
|
||||
import { IRouter } from '../../../../src/core/server';
|
||||
import { SERVER_SEARCH_ROUTE_PATH } from '../../common';
|
||||
|
||||
export function registerServerSearchRoute(router: IRouter, data: DataPluginStart) {
|
||||
router.get(
|
||||
{
|
||||
path: SERVER_SEARCH_ROUTE_PATH,
|
||||
validate: {
|
||||
query: schema.object({
|
||||
index: schema.maybe(schema.string()),
|
||||
field: schema.maybe(schema.string()),
|
||||
}),
|
||||
},
|
||||
},
|
||||
async (context, request, response) => {
|
||||
const { index, field } = request.query;
|
||||
// Run a synchronous search server side, by enforcing a high keepalive and waiting for completion.
|
||||
// If you wish to run the search with polling (in basic+), you'd have to poll on the search API.
|
||||
// Please reach out to the @app-arch-team if you need this to be implemented.
|
||||
const res = await data.search.search(
|
||||
context,
|
||||
{
|
||||
params: {
|
||||
index,
|
||||
body: {
|
||||
aggs: {
|
||||
'1': {
|
||||
avg: {
|
||||
field,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
waitForCompletionTimeout: '5m',
|
||||
keepAlive: '5m',
|
||||
},
|
||||
} as IEsSearchRequest,
|
||||
{}
|
||||
);
|
||||
|
||||
return response.ok({
|
||||
body: {
|
||||
aggs: (res as IEsSearchResponse).rawResponse.aggregations,
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
34
examples/search_examples/server/types.ts
Normal file
34
examples/search_examples/server/types.ts
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
// Rename PluginStart to something better
|
||||
import { PluginSetup, PluginStart } from '../../../src/plugins/data/server';
|
||||
|
||||
export interface SearchExamplesPluginSetupDeps {
|
||||
data: PluginSetup;
|
||||
}
|
||||
|
||||
export interface SearchExamplesPluginStartDeps {
|
||||
data: PluginStart;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface SearchExamplesPluginSetup {}
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface SearchExamplesPluginStart {}
|
16
examples/search_examples/tsconfig.json
Normal file
16
examples/search_examples/tsconfig.json
Normal file
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./target",
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": [
|
||||
"index.ts",
|
||||
"common/**/*.ts",
|
||||
"public/**/*.ts",
|
||||
"public/**/*.tsx",
|
||||
"server/**/*.ts",
|
||||
"../../typings/**/*",
|
||||
],
|
||||
"exclude": []
|
||||
}
|
|
@ -31,5 +31,13 @@ export interface IEsSearchRequest extends IKibanaSearchRequest {
|
|||
}
|
||||
|
||||
export interface IEsSearchResponse extends IKibanaSearchResponse {
|
||||
/**
|
||||
* Indicates whether async search is still in flight
|
||||
*/
|
||||
isRunning?: boolean;
|
||||
/**
|
||||
* Indicates whether the results returned are complete or partial
|
||||
*/
|
||||
isPartial?: boolean;
|
||||
rawResponse: SearchResponse<any>;
|
||||
}
|
||||
|
|
|
@ -770,6 +770,8 @@ export interface IEsSearchRequest extends IKibanaSearchRequest {
|
|||
//
|
||||
// @public (undocumented)
|
||||
export interface IEsSearchResponse extends IKibanaSearchResponse {
|
||||
isPartial?: boolean;
|
||||
isRunning?: boolean;
|
||||
// (undocumented)
|
||||
rawResponse: SearchResponse_2<any>;
|
||||
}
|
||||
|
@ -1213,11 +1215,10 @@ export type InputTimeRange = TimeRange | {
|
|||
// @public (undocumented)
|
||||
export type ISearch = (request: IKibanaSearchRequest, options?: ISearchOptions) => Observable<IKibanaSearchResponse>;
|
||||
|
||||
// Warning: (ae-forgotten-export) The symbol "IStrategyOptions" needs to be exported by the entry point index.d.ts
|
||||
// Warning: (ae-missing-release-tag) "ISearchGeneric" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export type ISearchGeneric = (request: IEsSearchRequest, options?: IStrategyOptions) => Observable<IEsSearchResponse>;
|
||||
export type ISearchGeneric = (request: IEsSearchRequest, options?: ISearchOptions) => Observable<IEsSearchResponse>;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "ISearchOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
|
@ -1225,6 +1226,8 @@ export type ISearchGeneric = (request: IEsSearchRequest, options?: IStrategyOpti
|
|||
export interface ISearchOptions {
|
||||
// (undocumented)
|
||||
signal?: AbortSignal;
|
||||
// (undocumented)
|
||||
strategy?: string;
|
||||
}
|
||||
|
||||
// Warning: (ae-forgotten-export) The symbol "SearchSource" needs to be exported by the entry point index.d.ts
|
||||
|
@ -1723,7 +1726,7 @@ export class SearchInterceptor {
|
|||
// (undocumented)
|
||||
protected readonly requestTimeout?: number | undefined;
|
||||
// (undocumented)
|
||||
protected runSearch(request: IEsSearchRequest, signal: AbortSignal): Observable<IEsSearchResponse>;
|
||||
protected runSearch(request: IEsSearchRequest, signal: AbortSignal, strategy?: string): Observable<IEsSearchResponse>;
|
||||
search(request: IEsSearchRequest, options?: ISearchOptions): Observable<IEsSearchResponse>;
|
||||
// (undocumented)
|
||||
protected setupTimers(options?: ISearchOptions): {
|
||||
|
|
|
@ -44,6 +44,7 @@ const createStartContractMock = () => {
|
|||
savedQueries: jest.fn() as any,
|
||||
state$: new Observable(),
|
||||
timefilter: timefilterServiceMock.createStartContract(),
|
||||
getEsQuery: jest.fn(),
|
||||
};
|
||||
|
||||
return startContract;
|
||||
|
|
|
@ -26,6 +26,9 @@ import { TimefilterService, TimefilterSetup } from './timefilter';
|
|||
import { createSavedQueryService } from './saved_query/saved_query_service';
|
||||
import { createQueryStateObservable } from './state_sync/create_global_query_observable';
|
||||
import { QueryStringManager, QueryStringContract } from './query_string';
|
||||
import { buildEsQuery, getEsQueryConfig } from '../../common';
|
||||
import { getUiSettings } from '../services';
|
||||
import { IndexPattern } from '..';
|
||||
|
||||
/**
|
||||
* Query Service
|
||||
|
@ -86,6 +89,16 @@ export class QueryService {
|
|||
savedQueries: createSavedQueryService(savedObjectsClient),
|
||||
state$: this.state$,
|
||||
timefilter: this.timefilter,
|
||||
getEsQuery: (indexPattern: IndexPattern) => {
|
||||
const timeFilter = this.timefilter.timefilter.createFilter(indexPattern);
|
||||
|
||||
return buildEsQuery(
|
||||
indexPattern,
|
||||
this.queryStringManager.getQuery(),
|
||||
[...this.filterManager.getFilters(), ...(timeFilter ? [timeFilter] : [])],
|
||||
getEsQueryConfig(getUiSettings())
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -17,11 +17,12 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { trimEnd } from 'lodash';
|
||||
import { BehaviorSubject, throwError, timer, Subscription, defer, from, Observable } from 'rxjs';
|
||||
import { finalize, filter } from 'rxjs/operators';
|
||||
import { ApplicationStart, Toast, ToastsStart, CoreStart } from 'kibana/public';
|
||||
import { getCombinedSignal, AbortError } from '../../common/utils';
|
||||
import { IEsSearchRequest, IEsSearchResponse } from '../../common/search';
|
||||
import { IEsSearchRequest, IEsSearchResponse, ES_SEARCH_STRATEGY } from '../../common/search';
|
||||
import { ISearchOptions } from './types';
|
||||
import { getLongQueryNotification } from './long_query_notification';
|
||||
import { SearchUsageCollector } from './collectors';
|
||||
|
@ -92,14 +93,20 @@ export class SearchInterceptor {
|
|||
|
||||
protected runSearch(
|
||||
request: IEsSearchRequest,
|
||||
signal: AbortSignal
|
||||
signal: AbortSignal,
|
||||
strategy?: string
|
||||
): Observable<IEsSearchResponse> {
|
||||
const { id, ...searchRequest } = request;
|
||||
const path = id != null ? `/internal/search/es/${id}` : '/internal/search/es';
|
||||
const method = 'POST';
|
||||
const path = trimEnd(`/internal/search/${strategy || ES_SEARCH_STRATEGY}/${id || ''}`, '/');
|
||||
const body = JSON.stringify(id != null ? {} : searchRequest);
|
||||
const response = this.deps.http.fetch({ path, method, body, signal });
|
||||
return from(response);
|
||||
return from(
|
||||
this.deps.http.fetch({
|
||||
method: 'POST',
|
||||
path,
|
||||
body,
|
||||
signal,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -120,7 +127,7 @@ export class SearchInterceptor {
|
|||
const { combinedSignal, cleanup } = this.setupTimers(options);
|
||||
this.pendingCount$.next(++this.pendingCount);
|
||||
|
||||
return this.runSearch(request, combinedSignal).pipe(
|
||||
return this.runSearch(request, combinedSignal, options?.strategy).pipe(
|
||||
finalize(() => {
|
||||
this.pendingCount$.next(--this.pendingCount);
|
||||
cleanup();
|
||||
|
|
|
@ -37,6 +37,7 @@ import { GetInternalStartServicesFn } from '../types';
|
|||
|
||||
export interface ISearchOptions {
|
||||
signal?: AbortSignal;
|
||||
strategy?: string;
|
||||
}
|
||||
|
||||
export type ISearch = (
|
||||
|
@ -44,14 +45,9 @@ export type ISearch = (
|
|||
options?: ISearchOptions
|
||||
) => Observable<IKibanaSearchResponse>;
|
||||
|
||||
// Service API types
|
||||
export interface IStrategyOptions extends ISearchOptions {
|
||||
strategy?: string;
|
||||
}
|
||||
|
||||
export type ISearchGeneric = (
|
||||
request: IEsSearchRequest,
|
||||
options?: IStrategyOptions
|
||||
options?: ISearchOptions
|
||||
) => Observable<IEsSearchResponse>;
|
||||
|
||||
export interface ISearchStartLegacy {
|
||||
|
|
|
@ -161,7 +161,12 @@ import {
|
|||
toAbsoluteDates,
|
||||
} from '../common';
|
||||
|
||||
export { EsaggsExpressionFunctionDefinition, ParsedInterval } from '../common';
|
||||
export {
|
||||
EsaggsExpressionFunctionDefinition,
|
||||
ParsedInterval,
|
||||
IEsSearchRequest,
|
||||
IEsSearchResponse,
|
||||
} from '../common';
|
||||
|
||||
export {
|
||||
ISearchStrategy,
|
||||
|
|
|
@ -78,7 +78,7 @@ describe('ES search strategy', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('returns total, loaded, and raw response', async () => {
|
||||
it('has all response parameters', async () => {
|
||||
const params = { index: 'logstash-*' };
|
||||
const esSearch = await esSearchStrategyProvider(mockConfig$, mockLogger);
|
||||
|
||||
|
@ -86,7 +86,8 @@ describe('ES search strategy', () => {
|
|||
params,
|
||||
});
|
||||
|
||||
expect(response).toHaveProperty('total');
|
||||
expect(response.isRunning).toBe(false);
|
||||
expect(response.isPartial).toBe(false);
|
||||
expect(response).toHaveProperty('loaded');
|
||||
expect(response).toHaveProperty('rawResponse');
|
||||
});
|
||||
|
|
|
@ -30,7 +30,7 @@ export const esSearchStrategyProvider = (
|
|||
): ISearchStrategy => {
|
||||
return {
|
||||
search: async (context, request, options) => {
|
||||
logger.info(`search ${JSON.stringify(request.params)}`);
|
||||
logger.info(`search ${request.params?.index}`);
|
||||
const config = await config$.pipe(first()).toPromise();
|
||||
const defaultParams = getDefaultSearchParams(config);
|
||||
|
||||
|
@ -56,7 +56,12 @@ export const esSearchStrategyProvider = (
|
|||
|
||||
// The above query will either complete or timeout and throw an error.
|
||||
// There is no progress indication on this api.
|
||||
return { rawResponse, ...getTotalLoaded(rawResponse._shards) };
|
||||
return {
|
||||
isPartial: false,
|
||||
isRunning: false,
|
||||
rawResponse,
|
||||
...getTotalLoaded(rawResponse._shards),
|
||||
};
|
||||
} catch (e) {
|
||||
if (usage) usage.trackError();
|
||||
throw e;
|
||||
|
|
|
@ -369,6 +369,30 @@ export function getTotalLoaded({ total, failed, successful }: ShardsResponse): {
|
|||
loaded: number;
|
||||
};
|
||||
|
||||
// Warning: (ae-forgotten-export) The symbol "IKibanaSearchRequest" needs to be exported by the entry point index.d.ts
|
||||
// Warning: (ae-missing-release-tag) "IEsSearchRequest" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export interface IEsSearchRequest extends IKibanaSearchRequest {
|
||||
// (undocumented)
|
||||
indexType?: string;
|
||||
// Warning: (ae-forgotten-export) The symbol "ISearchRequestParams" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// (undocumented)
|
||||
params?: ISearchRequestParams;
|
||||
}
|
||||
|
||||
// Warning: (ae-forgotten-export) The symbol "IKibanaSearchResponse" needs to be exported by the entry point index.d.ts
|
||||
// Warning: (ae-missing-release-tag) "IEsSearchResponse" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export interface IEsSearchResponse extends IKibanaSearchResponse {
|
||||
isPartial?: boolean;
|
||||
isRunning?: boolean;
|
||||
// (undocumented)
|
||||
rawResponse: SearchResponse<any>;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "IFieldFormatsRegistry" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
|
@ -547,8 +571,6 @@ export interface ISearchSetup {
|
|||
export interface ISearchStart {
|
||||
getSearchStrategy: (name: string) => ISearchStrategy;
|
||||
// Warning: (ae-forgotten-export) The symbol "RequestHandlerContext" needs to be exported by the entry point index.d.ts
|
||||
// Warning: (ae-forgotten-export) The symbol "IKibanaSearchRequest" needs to be exported by the entry point index.d.ts
|
||||
// Warning: (ae-forgotten-export) The symbol "IKibanaSearchResponse" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// (undocumented)
|
||||
search: (context: RequestHandlerContext, request: IKibanaSearchRequest, options: ISearchOptions) => Promise<IKibanaSearchResponse>;
|
||||
|
@ -560,9 +582,6 @@ export interface ISearchStart {
|
|||
export interface ISearchStrategy {
|
||||
// (undocumented)
|
||||
cancel?: (context: RequestHandlerContext, id: string) => Promise<void>;
|
||||
// Warning: (ae-forgotten-export) The symbol "IEsSearchRequest" needs to be exported by the entry point index.d.ts
|
||||
// Warning: (ae-forgotten-export) The symbol "IEsSearchResponse" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// (undocumented)
|
||||
search: (context: RequestHandlerContext, request: IEsSearchRequest, options?: ISearchOptions) => Promise<IEsSearchResponse>;
|
||||
}
|
||||
|
@ -817,13 +836,13 @@ export function usageProvider(core: CoreSetup_2): SearchUsage;
|
|||
// src/plugins/data/server/index.ts:101:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts
|
||||
// src/plugins/data/server/index.ts:127:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts
|
||||
// src/plugins/data/server/index.ts:127:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts
|
||||
// src/plugins/data/server/index.ts:180:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts
|
||||
// src/plugins/data/server/index.ts:181:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts
|
||||
// src/plugins/data/server/index.ts:182:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts
|
||||
// src/plugins/data/server/index.ts:183:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts
|
||||
// src/plugins/data/server/index.ts:184:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts
|
||||
// src/plugins/data/server/index.ts:185:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts
|
||||
// src/plugins/data/server/index.ts:188:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts
|
||||
// src/plugins/data/server/index.ts:185:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts
|
||||
// src/plugins/data/server/index.ts:186:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts
|
||||
// src/plugins/data/server/index.ts:187:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts
|
||||
// src/plugins/data/server/index.ts:188:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts
|
||||
// src/plugins/data/server/index.ts:189:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts
|
||||
// src/plugins/data/server/index.ts:190:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts
|
||||
// src/plugins/data/server/index.ts:193:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
|
||||
|
|
|
@ -4,9 +4,4 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export {
|
||||
EnhancedSearchParams,
|
||||
IEnhancedEsSearchRequest,
|
||||
IAsyncSearchRequest,
|
||||
IAsyncSearchResponse,
|
||||
} from './search';
|
||||
export { EnhancedSearchParams, IEnhancedEsSearchRequest, IAsyncSearchRequest } from './search';
|
||||
|
|
|
@ -4,9 +4,4 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export {
|
||||
EnhancedSearchParams,
|
||||
IEnhancedEsSearchRequest,
|
||||
IAsyncSearchRequest,
|
||||
IAsyncSearchResponse,
|
||||
} from './types';
|
||||
export { EnhancedSearchParams, IEnhancedEsSearchRequest, IAsyncSearchRequest } from './types';
|
||||
|
|
|
@ -4,11 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import {
|
||||
IEsSearchRequest,
|
||||
IEsSearchResponse,
|
||||
ISearchRequestParams,
|
||||
} from '../../../../../src/plugins/data/common';
|
||||
import { IEsSearchRequest, ISearchRequestParams } from '../../../../../src/plugins/data/common';
|
||||
|
||||
export interface EnhancedSearchParams extends ISearchRequestParams {
|
||||
ignoreThrottled: boolean;
|
||||
|
@ -23,17 +19,6 @@ export interface IAsyncSearchRequest extends IEsSearchRequest {
|
|||
params?: EnhancedSearchParams;
|
||||
}
|
||||
|
||||
export interface IAsyncSearchResponse extends IEsSearchResponse {
|
||||
/**
|
||||
* Indicates whether async search is still in flight
|
||||
*/
|
||||
is_running?: boolean;
|
||||
/**
|
||||
* Indicates whether the results returned are complete or partial
|
||||
*/
|
||||
is_partial?: boolean;
|
||||
}
|
||||
|
||||
export interface IEnhancedEsSearchRequest extends IEsSearchRequest {
|
||||
/**
|
||||
* Used to determine whether to use the _rollups_search or a regular search endpoint.
|
||||
|
|
|
@ -72,8 +72,8 @@ describe('EnhancedSearchInterceptor', () => {
|
|||
{
|
||||
time: 10,
|
||||
value: {
|
||||
is_partial: false,
|
||||
is_running: false,
|
||||
isPartial: false,
|
||||
isRunning: false,
|
||||
id: 1,
|
||||
rawResponse: {
|
||||
took: 1,
|
||||
|
@ -99,8 +99,8 @@ describe('EnhancedSearchInterceptor', () => {
|
|||
{
|
||||
time: 10,
|
||||
value: {
|
||||
is_partial: false,
|
||||
is_running: true,
|
||||
isPartial: false,
|
||||
isRunning: true,
|
||||
id: 1,
|
||||
rawResponse: {
|
||||
took: 1,
|
||||
|
@ -110,8 +110,8 @@ describe('EnhancedSearchInterceptor', () => {
|
|||
{
|
||||
time: 20,
|
||||
value: {
|
||||
is_partial: false,
|
||||
is_running: false,
|
||||
isPartial: false,
|
||||
isRunning: false,
|
||||
id: 1,
|
||||
rawResponse: {
|
||||
took: 1,
|
||||
|
@ -144,8 +144,8 @@ describe('EnhancedSearchInterceptor', () => {
|
|||
{
|
||||
time: 10,
|
||||
value: {
|
||||
is_partial: true,
|
||||
is_running: false,
|
||||
isPartial: true,
|
||||
isRunning: false,
|
||||
id: 1,
|
||||
},
|
||||
},
|
||||
|
@ -168,8 +168,8 @@ describe('EnhancedSearchInterceptor', () => {
|
|||
{
|
||||
time: 500,
|
||||
value: {
|
||||
is_partial: false,
|
||||
is_running: false,
|
||||
isPartial: false,
|
||||
isRunning: false,
|
||||
id: 1,
|
||||
},
|
||||
},
|
||||
|
@ -194,16 +194,16 @@ describe('EnhancedSearchInterceptor', () => {
|
|||
{
|
||||
time: 10,
|
||||
value: {
|
||||
is_partial: false,
|
||||
is_running: true,
|
||||
isPartial: false,
|
||||
isRunning: true,
|
||||
id: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
time: 300,
|
||||
value: {
|
||||
is_partial: false,
|
||||
is_running: false,
|
||||
isPartial: false,
|
||||
isRunning: false,
|
||||
id: 1,
|
||||
},
|
||||
},
|
||||
|
@ -238,8 +238,8 @@ describe('EnhancedSearchInterceptor', () => {
|
|||
{
|
||||
time: 2000,
|
||||
value: {
|
||||
is_partial: false,
|
||||
is_running: false,
|
||||
isPartial: false,
|
||||
isRunning: false,
|
||||
id: 1,
|
||||
},
|
||||
},
|
||||
|
@ -262,16 +262,16 @@ describe('EnhancedSearchInterceptor', () => {
|
|||
{
|
||||
time: 10,
|
||||
value: {
|
||||
is_partial: false,
|
||||
is_running: true,
|
||||
isPartial: false,
|
||||
isRunning: true,
|
||||
id: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
time: 2000,
|
||||
value: {
|
||||
is_partial: false,
|
||||
is_running: false,
|
||||
isPartial: false,
|
||||
isRunning: false,
|
||||
id: 1,
|
||||
},
|
||||
},
|
||||
|
@ -302,8 +302,8 @@ describe('EnhancedSearchInterceptor', () => {
|
|||
{
|
||||
time: 10,
|
||||
value: {
|
||||
is_partial: false,
|
||||
is_running: true,
|
||||
isPartial: false,
|
||||
isRunning: true,
|
||||
id: 1,
|
||||
},
|
||||
},
|
||||
|
@ -311,8 +311,8 @@ describe('EnhancedSearchInterceptor', () => {
|
|||
time: 10,
|
||||
value: {
|
||||
error: 'oh no',
|
||||
is_partial: false,
|
||||
is_running: false,
|
||||
isPartial: false,
|
||||
isRunning: false,
|
||||
id: 1,
|
||||
},
|
||||
isError: true,
|
||||
|
@ -346,16 +346,16 @@ describe('EnhancedSearchInterceptor', () => {
|
|||
{
|
||||
time: 10,
|
||||
value: {
|
||||
is_partial: false,
|
||||
is_running: false,
|
||||
isPartial: false,
|
||||
isRunning: false,
|
||||
id: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
time: 20,
|
||||
value: {
|
||||
is_partial: false,
|
||||
is_running: false,
|
||||
isPartial: false,
|
||||
isRunning: false,
|
||||
id: 1,
|
||||
},
|
||||
},
|
||||
|
@ -380,8 +380,8 @@ describe('EnhancedSearchInterceptor', () => {
|
|||
{
|
||||
time: 250,
|
||||
value: {
|
||||
is_partial: true,
|
||||
is_running: true,
|
||||
isPartial: true,
|
||||
isRunning: true,
|
||||
id: 1,
|
||||
rawResponse: {
|
||||
took: 1,
|
||||
|
@ -391,8 +391,8 @@ describe('EnhancedSearchInterceptor', () => {
|
|||
{
|
||||
time: 2000,
|
||||
value: {
|
||||
is_partial: false,
|
||||
is_running: false,
|
||||
isPartial: false,
|
||||
isRunning: false,
|
||||
id: 1,
|
||||
rawResponse: {
|
||||
took: 1,
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { Observable, throwError, EMPTY, timer, from } from 'rxjs';
|
||||
import { throwError, EMPTY, timer, from } from 'rxjs';
|
||||
import { mergeMap, expand, takeUntil, finalize, tap } from 'rxjs/operators';
|
||||
import { getLongQueryNotification } from './long_query_notification';
|
||||
import {
|
||||
|
@ -14,7 +14,7 @@ import {
|
|||
} from '../../../../../src/plugins/data/public';
|
||||
import { AbortError, toPromise } from '../../../../../src/plugins/data/common';
|
||||
import { IAsyncSearchOptions } from '.';
|
||||
import { IAsyncSearchRequest, IAsyncSearchResponse } from '../../common';
|
||||
import { IAsyncSearchRequest } from '../../common';
|
||||
|
||||
export class EnhancedSearchInterceptor extends SearchInterceptor {
|
||||
/**
|
||||
|
@ -67,7 +67,7 @@ export class EnhancedSearchInterceptor extends SearchInterceptor {
|
|||
public search(
|
||||
request: IAsyncSearchRequest,
|
||||
{ pollInterval = 1000, ...options }: IAsyncSearchOptions = {}
|
||||
): Observable<IAsyncSearchResponse> {
|
||||
) {
|
||||
let { id } = request;
|
||||
|
||||
request.params = {
|
||||
|
@ -80,15 +80,15 @@ export class EnhancedSearchInterceptor extends SearchInterceptor {
|
|||
|
||||
this.pendingCount$.next(++this.pendingCount);
|
||||
|
||||
return (this.runSearch(request, combinedSignal) as Observable<IAsyncSearchResponse>).pipe(
|
||||
expand((response: IAsyncSearchResponse) => {
|
||||
return this.runSearch(request, combinedSignal, options?.strategy).pipe(
|
||||
expand((response) => {
|
||||
// If the response indicates of an error, stop polling and complete the observable
|
||||
if (!response || (!response.is_running && response.is_partial)) {
|
||||
if (!response || (!response.isRunning && response.isPartial)) {
|
||||
return throwError(new AbortError());
|
||||
}
|
||||
|
||||
// If the response indicates it is complete, stop polling and complete the observable
|
||||
if (!response.is_running) {
|
||||
if (!response.isRunning) {
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
|
@ -97,7 +97,7 @@ export class EnhancedSearchInterceptor extends SearchInterceptor {
|
|||
return timer(pollInterval).pipe(
|
||||
// Send future requests using just the ID from the response
|
||||
mergeMap(() => {
|
||||
return this.runSearch({ id }, combinedSignal) as Observable<IAsyncSearchResponse>;
|
||||
return this.runSearch({ id }, combinedSignal, options?.strategy);
|
||||
})
|
||||
);
|
||||
}),
|
||||
|
|
|
@ -128,8 +128,8 @@ async function asyncSearch(
|
|||
|
||||
return {
|
||||
id,
|
||||
is_partial,
|
||||
is_running,
|
||||
isPartial: is_partial,
|
||||
isRunning: is_running,
|
||||
rawResponse: shimHitsTotal(response),
|
||||
...getTotalLoaded(response._shards),
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue