[ML] DF Analytics Outlier detection results: improve handling of text fields (#55002)

* add keyword suffix to fieldName when both text and keyword

* update exploration jest test
This commit is contained in:
Melissa Alvarez 2020-01-16 10:32:27 -05:00 committed by GitHub
parent e60289f611
commit b9814bfb76
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 60 additions and 14 deletions

View file

@ -7,6 +7,8 @@
import { shallow } from 'enzyme';
import React from 'react';
import { DATA_FRAME_TASK_STATE } from '../../../analytics_management/components/analytics_list/common';
import { KibanaContext } from '../../../../../contexts/kibana';
import { kibanaContextValueMock } from '../../../../../contexts/kibana/__mocks__/kibana_context_value';
jest.mock('../../../../../contexts/ui/use_ui_chrome_context');
jest.mock('ui/new_platform');
@ -22,7 +24,9 @@ jest.mock('react', () => {
describe('Data Frame Analytics: <Exploration />', () => {
test('Minimal initialization', () => {
const wrapper = shallow(
<Exploration jobId="the-job-id" jobStatus={DATA_FRAME_TASK_STATE.STOPPED} />
<KibanaContext.Provider value={kibanaContextValueMock}>
<Exploration jobId="the-job-id" jobStatus={DATA_FRAME_TASK_STATE.STOPPED} />
</KibanaContext.Provider>
);
// Without the jobConfig being loaded, the component will just return empty.
expect(wrapper.text()).toMatch('');

View file

@ -55,6 +55,7 @@ import {
SEARCH_SIZE,
defaultSearchQuery,
} from '../../../../common';
import { isKeywordAndTextType } from '../../../../common/fields';
import { getOutlierScoreFieldName } from './common';
import { useExploreData, TableItem } from './use_explore_data';
@ -64,6 +65,10 @@ import {
} from '../../../analytics_management/components/analytics_list/common';
import { getTaskStateBadge } from '../../../analytics_management/components/analytics_list/columns';
import { SavedSearchQuery } from '../../../../../contexts/kibana';
import { getIndexPatternIdFromName } from '../../../../../util/index_utils';
import { IIndexPattern } from '../../../../../../../../../../../src/plugins/data/common/index_patterns';
import { newJobCapsService } from '../../../../../services/new_job_capabilities_service';
import { useKibanaContext } from '../../../../../contexts/kibana';
const FEATURE_INFLUENCE = 'feature_influence';
@ -110,6 +115,19 @@ export const Exploration: FC<Props> = React.memo(({ jobId, jobStatus }) => {
const [searchError, setSearchError] = useState<any>(undefined);
const [searchString, setSearchString] = useState<string | undefined>(undefined);
const kibanaContext = useKibanaContext();
const initializeJobCapsService = async () => {
if (jobConfig !== undefined) {
const sourceIndex = jobConfig.source.index[0];
const indexPatternId = getIndexPatternIdFromName(sourceIndex) || sourceIndex;
const indexPattern: IIndexPattern = await kibanaContext.indexPatterns.get(indexPatternId);
if (indexPattern !== undefined) {
await newJobCapsService.initializeFromIndexPattern(indexPattern, false, false);
}
}
};
useEffect(() => {
(async function() {
const analyticsConfigs: GetDataFrameAnalyticsResponse = await ml.dataFrameAnalytics.getDataFrameAnalytics(
@ -124,6 +142,10 @@ export const Exploration: FC<Props> = React.memo(({ jobId, jobStatus }) => {
})();
}, []);
useEffect(() => {
initializeJobCapsService();
}, [jobConfig && jobConfig.id]);
const [selectedFields, setSelectedFields] = useState([] as EsFieldName[]);
const [isColumnsPopoverVisible, setColumnsPopoverVisible] = useState(false);
@ -293,10 +315,16 @@ export const Exploration: FC<Props> = React.memo(({ jobId, jobStatus }) => {
if (jobConfig !== undefined) {
const outlierScoreFieldName = getOutlierScoreFieldName(jobConfig);
const outlierScoreFieldSelected = selectedFields.includes(outlierScoreFieldName);
let requiresKeyword = false;
const field = outlierScoreFieldSelected ? outlierScoreFieldName : selectedFields[0];
const direction = outlierScoreFieldSelected ? SORT_DIRECTION.DESC : SORT_DIRECTION.ASC;
loadExploreData({ field, direction, searchQuery });
if (outlierScoreFieldSelected === false) {
requiresKeyword = isKeywordAndTextType(field);
}
loadExploreData({ field, direction, searchQuery, requiresKeyword });
}
}, [JSON.stringify(searchQuery)]);
@ -307,10 +335,16 @@ export const Exploration: FC<Props> = React.memo(({ jobId, jobStatus }) => {
if (jobConfig !== undefined && columns.length > 0 && !selectedFields.includes(sortField)) {
const outlierScoreFieldName = getOutlierScoreFieldName(jobConfig);
const outlierScoreFieldSelected = selectedFields.includes(outlierScoreFieldName);
let requiresKeyword = false;
const field = outlierScoreFieldSelected ? outlierScoreFieldName : selectedFields[0];
const direction = outlierScoreFieldSelected ? SORT_DIRECTION.DESC : SORT_DIRECTION.ASC;
loadExploreData({ field, direction, searchQuery });
if (outlierScoreFieldSelected === false) {
requiresKeyword = isKeywordAndTextType(field);
}
loadExploreData({ field, direction, searchQuery, requiresKeyword });
return;
}
}, [jobConfig, columns.length, sortField, sortDirection, tableItems.length]);
@ -334,8 +368,17 @@ export const Exploration: FC<Props> = React.memo(({ jobId, jobStatus }) => {
setPageIndex(index);
setPageSize(size);
if (sort.field !== sortField || sort.direction !== sortDirection) {
loadExploreData({ ...sort, searchQuery });
if (
(sort.field !== sortField || sort.direction !== sortDirection) &&
jobConfig !== undefined
) {
const outlierScoreFieldName = getOutlierScoreFieldName(jobConfig);
let requiresKeyword = false;
if (outlierScoreFieldName !== sort.field) {
requiresKeyword = isKeywordAndTextType(sort.field);
}
loadExploreData({ ...sort, searchQuery, requiresKeyword });
}
};
}

View file

@ -23,18 +23,12 @@ import {
defaultSearchQuery,
SearchQuery,
} from '../../../../common';
import { LoadExploreDataArg } from '../../../../common/analytics';
import { getOutlierScoreFieldName } from './common';
import { SavedSearchQuery } from '../../../../../contexts/kibana';
export type TableItem = Record<string, any>;
interface LoadExploreDataArg {
field: string;
direction: SortDirection;
searchQuery: SavedSearchQuery;
}
export interface UseExploreDataReturnType {
errorMessage: string;
loadExploreData: (arg: LoadExploreDataArg) => void;
@ -55,7 +49,12 @@ export const useExploreData = (
const [sortField, setSortField] = useState<string>('');
const [sortDirection, setSortDirection] = useState<SortDirection>(SORT_DIRECTION.ASC);
const loadExploreData = async ({ field, direction, searchQuery }: LoadExploreDataArg) => {
const loadExploreData = async ({
field,
direction,
searchQuery,
requiresKeyword,
}: LoadExploreDataArg) => {
if (jobConfig !== undefined) {
setErrorMessage('');
setStatus(INDEX_STATUS.LOADING);
@ -70,7 +69,7 @@ export const useExploreData = (
if (field !== undefined) {
body.sort = [
{
[field]: {
[`${field}${requiresKeyword ? '.keyword' : ''}`]: {
order: direction,
},
},