mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[Enterprise Search] Don't include hidden/nested documents in document counts for Indices (#137900)
This commit is contained in:
parent
d03c6b5fd6
commit
5df2801625
13 changed files with 62 additions and 6 deletions
|
@ -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: {
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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"> {option.total?.docs?.count ?? '-'}</EuiTextColor>
|
||||
:<EuiTextColor color="subdued"> {option.count ?? '-'}</EuiTextColor>
|
||||
</span>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem data-test-subj="optionStorage">
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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[] = [
|
||||
|
|
|
@ -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',
|
||||
}),
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue