[App Search][Nested Fields / Object fields]Use field capabilities (#135951)

This commit is contained in:
Aurélien FOUCRET 2022-07-08 13:15:46 +02:00 committed by GitHub
parent daec70ba1c
commit 188b9e094d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 91 additions and 47 deletions

View file

@ -15,11 +15,23 @@ describe('buildSearchUIConfig', () => {
it('builds a configuration object for Search UI', () => {
const connector = {};
const schema = {
foo: SchemaType.Text,
bar: SchemaType.Number,
foo: {
type: SchemaType.Text,
capabilities: {
snippet: true,
facet: true,
},
},
bar: {
type: SchemaType.Number,
capabilities: {
snippet: false,
facet: false,
},
},
};
const fields = {
filterFields: ['fieldA', 'fieldB'],
filterFields: ['foo', 'bar'],
sortFields: [],
};
@ -32,13 +44,9 @@ describe('buildSearchUIConfig', () => {
sortField: 'id',
},
searchQuery: {
disjunctiveFacets: ['fieldA', 'fieldB'],
disjunctiveFacets: ['foo'],
facets: {
fieldA: {
size: 30,
type: 'value',
},
fieldB: {
foo: {
size: 30,
type: 'value',
},
@ -50,7 +58,6 @@ describe('buildSearchUIConfig', () => {
foo: {
raw: {},
snippet: {
fallback: true,
size: 300,
},
},

View file

@ -7,26 +7,34 @@
import type { APIConnector, SortDirection } from '@elastic/search-ui';
import { Schema } from '../../../../shared/schema/types';
import { SchemaType, AdvancedSchema } from '../../../../shared/schema/types';
import { Fields } from './types';
export const buildSearchUIConfig = (
apiConnector: APIConnector,
schema: Schema,
schema: AdvancedSchema,
fields: Fields,
initialState = { sortDirection: 'desc' as SortDirection, sortField: 'id' }
) => {
const facets = fields.filterFields.reduce((facetsConfig, fieldName) => {
// Geolocation fields do not support value facets https://www.elastic.co/guide/en/app-search/current/facets.html
if (schema[fieldName] === 'geolocation') {
return facetsConfig;
}
return {
...facetsConfig,
[fieldName]: { type: 'value', size: 30 },
};
}, {});
const facets = fields.filterFields
.filter((fieldName) => !!schema[fieldName] && schema[fieldName].type !== SchemaType.Geolocation)
.filter((fieldName) => !!schema[fieldName].capabilities.facet)
.reduce((facetsConfig, fieldName) => {
return {
...facetsConfig,
[fieldName]: { type: 'value', size: 30 },
};
}, {});
const resultFields = Object.entries(schema)
.filter(([, schemaField]) => schemaField.type !== SchemaType.Nested)
.reduce((acc, [fieldName, schemaField]) => {
if (schemaField.capabilities.snippet) {
return { ...acc, [fieldName]: { raw: {}, snippet: { size: 300 } } };
}
return { ...acc, [fieldName]: { raw: {} } };
}, {});
return {
alwaysSearchOnInitialLoad: true,
@ -34,25 +42,9 @@ export const buildSearchUIConfig = (
trackUrlState: false,
initialState,
searchQuery: {
disjunctiveFacets: fields.filterFields,
disjunctiveFacets: Object.keys(facets),
facets,
result_fields: Object.keys(schema).reduce((acc: { [key: string]: object }, key: string) => {
if (schema[key] === 'text') {
// Only text fields support snippets
acc[key] = {
snippet: {
size: 300,
fallback: true,
},
raw: {},
};
} else {
acc[key] = {
raw: {},
};
}
return acc;
}, {}),
result_fields: resultFields,
},
};
};

View file

@ -52,14 +52,20 @@ export const CustomizationModal: React.FC<Props> = ({
sortFields.map(fieldNameToComboBoxOption)
);
const engineSchema = engine.schema || {};
const schema = engine.advancedSchema || {};
const selectableFilterFields = useMemo(
() => Object.keys(engineSchema).map(fieldNameToComboBoxOption),
[engineSchema]
() =>
Object.keys(schema)
.filter((fieldName) => schema[fieldName].capabilities.filter)
.map(fieldNameToComboBoxOption),
[schema]
);
const selectableSortFields = useMemo(
() => Object.keys(engineSchema).map(fieldNameToComboBoxOption),
[engineSchema]
() =>
Object.keys(schema)
.filter((fieldName) => schema[fieldName].capabilities.sort)
.map(fieldNameToComboBoxOption),
[schema]
);
return (

View file

@ -100,7 +100,7 @@ export const SearchExperience: React.FC = () => {
const searchProviderConfig = buildSearchUIConfig(
connector,
engine.schema || {},
engine.advancedSchema || {},
fields,
initialState
);

View file

@ -41,6 +41,19 @@ describe('EngineLogic', () => {
isMeta: false,
invalidBoosts: false,
schema: { test: SchemaType.Text },
advancedSchema: {
test: {
type: SchemaType.Text,
capabilities: {
fulltext: true,
filter: true,
facet: true,
sort: true,
snippet: true,
boost: true,
},
},
},
apiTokens: [],
apiKey: 'some-key',
adaptive_relevance_suggestions_active: true,

View file

@ -5,7 +5,12 @@
* 2.0.
*/
import { Schema, SchemaConflicts, IIndexingStatus } from '../../../shared/schema/types';
import {
Schema,
SchemaConflicts,
IIndexingStatus,
AdvancedSchema,
} from '../../../shared/schema/types';
import { ApiToken } from '../credentials/types';
export enum EngineTypes {
@ -47,6 +52,7 @@ export interface EngineDetails extends Engine {
apiKey: string;
elasticsearchIndexName?: string;
schema: Schema;
advancedSchema: AdvancedSchema;
schemaConflicts?: SchemaConflicts;
unconfirmedFields?: string[];
activeReindexJob?: IIndexingStatus;

View file

@ -26,6 +26,7 @@ const fieldTypeToTokenMap = {
[InternalSchemaType.Location]: 'tokenGeo',
[SchemaType.Date]: 'tokenDate',
[InternalSchemaType.Date]: 'tokenDate',
[InternalSchemaType.Nested]: 'tokenNested',
};
export const ResultToken: React.FC<Props> = ({ fieldType }) => {

View file

@ -14,6 +14,7 @@ export enum SchemaType {
Number = 'number',
Geolocation = 'geolocation',
Date = 'date',
Nested = 'nested',
}
// Certain API endpoints will use these internal type names, which map to the external names above
export enum InternalSchemaType {
@ -21,6 +22,7 @@ export enum InternalSchemaType {
Float = 'float',
Location = 'location',
Date = 'date',
Nested = 'nested',
}
export type Schema = Record<string, SchemaType>;
@ -62,3 +64,20 @@ export interface FieldCoercionError {
error: string;
}
export type FieldCoercionErrors = Record<string, FieldCoercionError[]>;
export interface SchemaFieldCapabilities {
fulltext?: boolean;
filter?: boolean;
facet?: boolean;
sort?: boolean;
snippet?: boolean;
boost?: boolean;
}
export interface AdvancedSchemaField {
type: SchemaType;
nestedPath?: string;
capabilities: SchemaFieldCapabilities;
}
export type AdvancedSchema = Record<string, AdvancedSchemaField>;