[Enterprise Search] Don't include hidden/nested documents in document counts for Indices (#137900)

This commit is contained in:
Byron Hulcher 2022-08-03 20:41:51 -04:00 committed by GitHub
parent d03c6b5fd6
commit 5df2801625
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 62 additions and 6 deletions

View file

@ -16,12 +16,13 @@ import { Connector } from './connectors';
import { Crawler } from './crawler';
export interface ElasticsearchIndex {
count: number; // Elasticsearch _count
health?: HealthStatus;
name: IndexName;
status?: IndicesStatsIndexMetadataState;
total: {
docs: {
count: number;
count: number; // Lucene count (includes nested documents)
deleted: number;
};
store: {

View file

@ -7,6 +7,8 @@
import dedent from 'dedent';
import { ElasticsearchIndexWithPrivileges } from '../../../../common/types/indices';
import { EngineCreationSteps } from '../components/engine_creation/engine_creation_logic';
import { SearchIndexSelectableOption } from '../components/engine_creation/search_index_selectable';
@ -32,8 +34,9 @@ export const DEFAULT_VALUES = {
selectedIndexFormatted: undefined,
};
export const mockElasticsearchIndices = [
export const mockElasticsearchIndices: ElasticsearchIndexWithPrivileges[] = [
{
count: 0,
health: 'yellow',
status: 'open',
name: 'search-my-index-1',
@ -51,6 +54,7 @@ export const mockElasticsearchIndices = [
},
},
{
count: 100,
health: 'green',
status: 'open',
name: 'my-index-2',
@ -68,6 +72,7 @@ export const mockElasticsearchIndices = [
},
},
{
count: 100,
health: 'green',
status: 'open',
name: 'search-my-index-2',
@ -85,6 +90,7 @@ export const mockElasticsearchIndices = [
},
},
{
count: 100,
health: 'green',
status: 'open',
name: 'alias-my-index-2',
@ -102,6 +108,7 @@ export const mockElasticsearchIndices = [
},
},
{
count: 100,
health: 'green',
status: 'open',
name: 'index-without-read-privilege',
@ -119,6 +126,7 @@ export const mockElasticsearchIndices = [
},
},
{
count: 100,
health: 'green',
status: 'open',
name: 'index-without-manage-privilege',
@ -136,6 +144,7 @@ export const mockElasticsearchIndices = [
},
},
{
count: 100,
health: 'green',
status: 'open',
name: 'alias-without-manage-privilege',
@ -156,6 +165,7 @@ export const mockElasticsearchIndices = [
export const mockSearchIndexOptions: SearchIndexSelectableOption[] = [
{
count: 0,
label: 'search-my-index-1',
health: 'yellow',
status: 'open',
@ -181,6 +191,7 @@ export const mockSearchIndexOptions: SearchIndexSelectableOption[] = [
},
},
{
count: 100,
label: 'my-index-2',
health: 'green',
status: 'open',
@ -207,6 +218,7 @@ export const mockSearchIndexOptions: SearchIndexSelectableOption[] = [
},
},
{
count: 100,
label: 'search-my-index-2',
health: 'green',
status: 'open',
@ -229,6 +241,7 @@ export const mockSearchIndexOptions: SearchIndexSelectableOption[] = [
},
},
{
count: 100,
label: 'alias-my-index-2',
health: 'green',
status: 'open',

View file

@ -15,6 +15,7 @@ import { shallow } from 'enzyme';
import { IndexStatusDetails, SearchIndexSelectableOption } from './search_index_selectable';
const mockOption: SearchIndexSelectableOption = {
count: 123,
label: 'string',
alias: true,
badge: {

View file

@ -45,6 +45,7 @@ export interface SearchIndexSelectableOption {
};
};
checked?: 'on';
count: number;
}
const healthColorsMap = {
@ -89,7 +90,7 @@ export const IndexStatusDetails: React.FC<IndexStatusDetailsProps> = ({ option }
{ defaultMessage: 'Docs count' }
)}
</b>
:<EuiTextColor color="subdued">&nbsp;{option.total?.docs?.count ?? '-'}</EuiTextColor>
:<EuiTextColor color="subdued">&nbsp;{option.count ?? '-'}</EuiTextColor>
</span>
</EuiFlexItem>
<EuiFlexItem data-test-subj="optionStorage">

View file

@ -91,6 +91,7 @@ export const formatIndicesToSelectable = (
label: index.alias ? 'Alias' : 'Index',
...(icon ? { icon } : {}),
},
count: index.count,
disabled: index.alias && !index.name.startsWith('search-'),
label: index.name,
health: index.health,

View file

@ -10,6 +10,7 @@ import { ElasticsearchIndexWithIngestion } from '../../../../common/types/indice
export const indices: ElasticsearchIndexWithIngestion[] = [
{
count: 1,
name: 'api',
total: {
docs: {
@ -39,6 +40,7 @@ export const indices: ElasticsearchIndexWithIngestion[] = [
status: ConnectorStatus.CONFIGURED,
sync_now: false,
},
count: 1,
name: 'connector',
total: {
docs: {
@ -49,6 +51,7 @@ export const indices: ElasticsearchIndexWithIngestion[] = [
},
},
{
count: 1,
crawler: {
id: '3',
index_name: 'crawler',

View file

@ -16,6 +16,7 @@ import {
} from '../types';
export const apiIndex: ApiViewIndex = {
count: 1,
ingestionMethod: IngestionMethod.API,
ingestionStatus: IngestionStatus.CONNECTED,
lastUpdated: null,
@ -48,6 +49,7 @@ export const connectorIndex: ConnectorViewIndex = {
status: ConnectorStatus.CONFIGURED,
sync_now: false,
},
count: 1,
ingestionMethod: IngestionMethod.CONNECTOR,
ingestionStatus: IngestionStatus.INCOMPLETE,
lastUpdated: 'never',
@ -61,6 +63,7 @@ export const connectorIndex: ConnectorViewIndex = {
},
};
export const crawlerIndex: CrawlerViewIndex = {
count: 1,
crawler: {
id: '3',
index_name: 'crawler',

View file

@ -23,7 +23,7 @@ interface TotalStatsProps {
export const TotalStats: React.FC<TotalStatsProps> = ({ ingestionType, additionalItems = [] }) => {
const { indexData, isError, isLoading } = useValues(OverviewLogic);
const documentCount = indexData?.total.docs.count ?? 0;
const documentCount = indexData?.count ?? 0;
const hideStats = isLoading || isError;
const stats: EuiStatProps[] = [

View file

@ -72,7 +72,7 @@ const columns: Array<EuiBasicTableColumn<ElasticsearchViewIndex>> = [
width: '10%',
},
{
field: 'total.docs.count',
field: 'count',
name: i18n.translate('xpack.enterpriseSearch.content.searchIndices.docsCount.columnTitle', {
defaultMessage: 'Docs count',
}),

View file

@ -24,6 +24,7 @@ jest.mock('../crawler/fetch_crawlers', () => ({
describe('fetchIndex lib function', () => {
const mockClient = {
asCurrentUser: {
count: jest.fn().mockReturnValue({ count: 100 }),
index: jest.fn(),
indices: {
get: jest.fn(),
@ -60,6 +61,7 @@ describe('fetchIndex lib function', () => {
const result = {
aliases: [],
count: 100,
health: 'green',
name: 'index_name',
status: 'open',

View file

@ -20,11 +20,17 @@ export const fetchIndex = async (
const indexDataResult = await client.asCurrentUser.indices.get({ index });
const indexData = indexDataResult[index];
const { indices } = await client.asCurrentUser.indices.stats({ index });
const { count } = await client.asCurrentUser.count({ index });
if (!indices || !indices[index] || !indexData) {
throw new Error('404');
}
const indexStats = indices[index];
const indexResult = mapIndexStats(indexData, indexStats, index);
const indexResult = {
count,
...mapIndexStats(indexData, indexStats, index),
};
const connector = await fetchConnectorByIndexName(client, index);
if (connector) {

View file

@ -20,6 +20,7 @@ describe('fetchIndices lib function', () => {
security: {
hasPrivileges: jest.fn(),
},
count: jest.fn().mockReturnValue({ count: 100 }),
},
asInternalUser: {},
};
@ -75,6 +76,7 @@ describe('fetchIndices lib function', () => {
fetchIndices(mockClient as unknown as IScopedClusterClient, 'search-*', false, true)
).resolves.toEqual([
{
count: 100,
health: 'green',
name: 'search-regular-index',
status: 'open',
@ -123,6 +125,7 @@ describe('fetchIndices lib function', () => {
fetchIndices(mockClient as unknown as IScopedClusterClient, 'search-*', true, true)
).resolves.toEqual([
{
count: 100,
health: 'green',
name: 'search-regular-index',
status: 'open',
@ -183,6 +186,7 @@ describe('fetchIndices lib function', () => {
fetchIndices(mockClient as unknown as IScopedClusterClient, 'search-*', false, true)
).resolves.toEqual([
{
count: 100,
health: 'green',
name: 'index-without-prefix',
status: 'open',
@ -200,6 +204,7 @@ describe('fetchIndices lib function', () => {
uuid: '83a81e7e-5955-4255-b008-5d6961203f57',
},
{
count: 100,
health: 'green',
name: 'search-aliased',
status: 'open',
@ -217,6 +222,7 @@ describe('fetchIndices lib function', () => {
uuid: '83a81e7e-5955-4255-b008-5d6961203f57',
},
{
count: 100,
health: 'green',
name: 'search-double-aliased',
status: 'open',
@ -234,6 +240,7 @@ describe('fetchIndices lib function', () => {
uuid: '83a81e7e-5955-4255-b008-5d6961203f57',
},
{
count: 100,
health: 'green',
name: 'second-index',
status: 'open',
@ -282,6 +289,7 @@ describe('fetchIndices lib function', () => {
fetchIndices(mockClient as unknown as IScopedClusterClient, 'search-*', false, false)
).resolves.toEqual([
{
count: 100,
health: 'green',
name: 'index-without-prefix',
status: 'open',
@ -299,6 +307,7 @@ describe('fetchIndices lib function', () => {
uuid: '83a81e7e-5955-4255-b008-5d6961203f57',
},
{
count: 100,
health: 'green',
name: 'second-index',
status: 'open',
@ -332,6 +341,7 @@ describe('fetchIndices lib function', () => {
fetchIndices(mockClient as unknown as IScopedClusterClient, 'search-*', false, true)
).resolves.toEqual([
{
count: 100,
health: undefined,
name: 'search-regular-index',
status: undefined,

View file

@ -34,6 +34,7 @@ export const mapIndexStats = (
size_in_bytes: sizeInBytes,
},
};
return {
aliases,
health: indexStats?.health,
@ -44,6 +45,16 @@ export const mapIndexStats = (
};
};
export const fetchIndexCounts = async (client: IScopedClusterClient, indicesNames: string[]) => {
// TODO: is there way to batch this? Passing multiple index names or a pattern still returns a singular count
const countPromises = indicesNames.map(async (indexName) => {
const { count } = await client.asCurrentUser.count({ index: indexName });
return { [indexName]: count };
});
const indexCountArray = await Promise.all(countPromises);
return indexCountArray.reduce((acc, current) => ({ ...acc, ...current }), {});
};
export const fetchIndices = async (
client: IScopedClusterClient,
indexPattern: string,
@ -97,6 +108,8 @@ export const fetchIndices = async (
],
});
const indexCounts = await fetchIndexCounts(client, indexAndAliasNames);
return indicesNames
.map((indexName: string) => {
const indexData = totalIndices[indexName];
@ -108,6 +121,7 @@ export const fetchIndices = async (
const indicesAndAliases = [] as ElasticsearchIndexWithPrivileges[];
indicesAndAliases.push({
name,
count: indexCounts[name] ?? 0,
alias: false,
privileges: { read: false, manage: false, ...indexPrivileges[name] },
...indexData,
@ -117,6 +131,7 @@ export const fetchIndices = async (
aliases.forEach((alias) => {
indicesAndAliases.push({
name: alias,
count: indexCounts[alias] ?? 0,
alias: true,
privileges: { read: false, manage: false, ...indexPrivileges[name] },
...indexData,