From ac3856cd03353a00c74c2c50e71fe446c9d33770 Mon Sep 17 00:00:00 2001 From: ryjiang Date: Thu, 11 Jul 2024 18:29:14 +0800 Subject: [PATCH] support dynamic fields selection Signed-off-by: ryjiang --- client/src/pages/databases/Databases.tsx | 8 ++- .../databases/collections/search/Search.tsx | 51 ++++++++++--------- .../collections/search/SearchGlobalParams.tsx | 44 ++++++++++------ client/src/utils/search.ts | 10 ++-- 4 files changed, 65 insertions(+), 48 deletions(-) diff --git a/client/src/pages/databases/Databases.tsx b/client/src/pages/databases/Databases.tsx index 90804f98..5aaba82f 100644 --- a/client/src/pages/databases/Databases.tsx +++ b/client/src/pages/databases/Databases.tsx @@ -16,7 +16,7 @@ import Search from './collections/search/Search'; import { dataContext, authContext } from '@/context'; import Collections from './collections/Collections'; import StatusIcon, { LoadingType } from '@/components/status/StatusIcon'; -import { ConsistencyLevelEnum } from '@/consts'; +import { ConsistencyLevelEnum, DYNAMIC_FIELD } from '@/consts'; import RefreshButton from './RefreshButton'; import CopyButton from '@/components/advancedSearch/CopyButton'; import { SearchParams } from './types'; @@ -74,6 +74,8 @@ const Databases = () => { // if search params not found, and the schema is ready, create new search params if (!searchParam && c.schema) { setSearchParams(prevParams => { + const scalarFields = c.schema.scalarFields.map(s => s.name); + return [ ...prevParams, { @@ -97,7 +99,9 @@ const Databases = () => { weightedParams: { weights: Array(c.schema.vectorFields.length).fill(0.5), }, - output_fields: c.schema.scalarFields.map(s => s.name), + output_fields: c.schema.enable_dynamic_field + ? [...scalarFields, DYNAMIC_FIELD] + : scalarFields, }, searchResult: null, searchLatency: 0, diff --git a/client/src/pages/databases/collections/search/Search.tsx b/client/src/pages/databases/collections/search/Search.tsx index 1ef93356..e344789f 100644 --- a/client/src/pages/databases/collections/search/Search.tsx +++ b/client/src/pages/databases/collections/search/Search.tsx @@ -168,7 +168,7 @@ const Search = (props: CollectionDataProps) => { // execute search const onSearchClicked = useCallback(async () => { - const params = buildSearchParams(searchParams, outputFields); + const params = buildSearchParams(searchParams); setTableLoading(true); try { @@ -179,7 +179,6 @@ const Search = (props: CollectionDataProps) => { setTableLoading(false); setSearchResult(res); - // setLatency(res.latency); } catch (err) { setTableLoading(false); } @@ -191,20 +190,20 @@ const Search = (props: CollectionDataProps) => { let primaryKeyField = 'id'; - const outputFields: string[] = useMemo(() => { - if (!searchParams || !searchParams.collection) { - return []; - } + // const outputFields: string[] = useMemo(() => { + // if (!searchParams || !searchParams.collection) { + // return []; + // } - const s = searchParams.collection.schema!; - const _outputFields = [...searchParams.globalParams.output_fields]; + // const s = searchParams.collection.schema!; + // const _outputFields = [...searchParams.globalParams.output_fields]; - if (s.enable_dynamic_field) { - _outputFields.push(DYNAMIC_FIELD); - } + // if (s.enable_dynamic_field) { + // _outputFields.push(DYNAMIC_FIELD); + // } - return _outputFields; - }, [JSON.stringify(searchParams)]); + // return _outputFields; + // }, [JSON.stringify(searchParams)]); const { pageSize, @@ -229,7 +228,16 @@ const Search = (props: CollectionDataProps) => { }, [JSON.stringify(searchParams), setCurrentPage]); const colDefinitions: ColDefinitionsType[] = useMemo(() => { - const orderArray = [primaryKeyField, 'id', 'score', ...outputFields]; + if (!searchParams || !searchParams.collection) { + return []; + } + // collection fields, combine static and dynamic fields + const orderArray = [ + primaryKeyField, + 'id', + 'score', + ...searchParams.globalParams.output_fields, + ]; return searchParams && searchParams.searchResult && @@ -278,7 +286,11 @@ const Search = (props: CollectionDataProps) => { }; }) : []; - }, [JSON.stringify({ searchParams, outputFields })]); + }, [ + JSON.stringify({ + searchParams, + }), + ]); // methods const handlePageChange = (e: any, page: number) => { @@ -410,10 +422,7 @@ const Search = (props: CollectionDataProps) => { onSlideChangeCommitted={() => { setHighlightField(''); }} - fields={searchParams.collection.schema.scalarFields} - outputFields={searchParams.collection.schema.scalarFields} searchParams={searchParams} - searchGlobalParams={searchParams.globalParams} handleFormChange={(params: any) => { searchParams.globalParams = params; setSearchParams({ ...searchParams }); @@ -496,11 +505,7 @@ const Search = (props: CollectionDataProps) => { params: { component: ( ), }, diff --git a/client/src/pages/databases/collections/search/SearchGlobalParams.tsx b/client/src/pages/databases/collections/search/SearchGlobalParams.tsx index b68553e5..86f24db9 100644 --- a/client/src/pages/databases/collections/search/SearchGlobalParams.tsx +++ b/client/src/pages/databases/collections/search/SearchGlobalParams.tsx @@ -4,24 +4,20 @@ import { Slider } from '@material-ui/core'; import CustomInput from '@/components/customInput/CustomInput'; import CustomSelector from '@/components/customSelector/CustomSelector'; import CustomMultiSelector from '@/components/customSelector/CustomMultiSelector'; - import { + DYNAMIC_FIELD, CONSISTENCY_LEVEL_OPTIONS, TOP_K_OPTIONS, RERANKER_OPTIONS, DataTypeStringEnum, } from '@/consts'; import { SearchParams, GlobalParams } from '../../types'; -import { FieldObject } from '@server/types'; export interface SearchGlobalProps { - searchGlobalParams: GlobalParams; searchParams: SearchParams; handleFormChange: (form: GlobalParams) => void; onSlideChange: (field: string) => void; onSlideChangeCommitted: () => void; - fields: FieldObject[]; - outputFields: FieldObject[]; } const UNSPORTED_GROUPBY_TYPES = [ @@ -34,13 +30,18 @@ const SearchGlobalParams = (props: SearchGlobalProps) => { // props const { searchParams, - searchGlobalParams, handleFormChange, onSlideChange, onSlideChangeCommitted, - fields, - outputFields, } = props; + // values + const searchGlobalParams = searchParams.globalParams; + const fields = searchParams.collection.schema?.scalarFields || []; + const outputFields = [ + ...(searchParams.collection.schema?.scalarFields || []), + ...(searchParams.collection.schema?.dynamicFields || []), + ]; + const selectedCount = searchParams.searchParams.filter( sp => sp.selected ).length; @@ -103,7 +104,11 @@ const SearchGlobalParams = (props: SearchGlobalProps) => { { - return { label: f.name, value: f.name }; + return { + label: + f.name === DYNAMIC_FIELD ? searchTrans('dynamicFields') : f.name, + value: f.name, + }; })} values={searchGlobalParams.output_fields} renderValue={selected => ( @@ -116,21 +121,28 @@ const SearchGlobalParams = (props: SearchGlobalProps) => { variant="filled" onChange={(e: { target: { value: unknown } }) => { // add value to output fields if not exist, remove if exist - const outputFields = [...searchGlobalParams.output_fields]; + const newOutputFields = [...searchGlobalParams.output_fields]; const values = e.target.value as string[]; const newFields = values.filter( - v => !outputFields.includes(v as string) + v => !newOutputFields.includes(v as string) ); - const removeFields = outputFields.filter( + const removeFields = newOutputFields.filter( v => !values.includes(v as string) ); - outputFields.push(...newFields); + newOutputFields.push(...newFields); removeFields.forEach(f => { - const index = outputFields.indexOf(f); - outputFields.splice(index, 1); + const index = newOutputFields.indexOf(f); + newOutputFields.splice(index, 1); + }); + + // sort output fields by schema order + newOutputFields.sort((a, b) => { + const aIndex = outputFields.findIndex(f => f.name === a); + const bIndex = outputFields.findIndex(f => f.name === b); + return aIndex - bIndex; }); - handleInputChange('output_fields', outputFields); + handleInputChange('output_fields', newOutputFields); }} /> diff --git a/client/src/utils/search.ts b/client/src/utils/search.ts index 4007733e..83959717 100644 --- a/client/src/utils/search.ts +++ b/client/src/utils/search.ts @@ -16,10 +16,7 @@ export const getVectorFieldOptions = (fields: FieldObject[]): FieldOption[] => { }; // new search: build search params -export const buildSearchParams = ( - searchParams: SearchParams, - output_fields: string[] -) => { +export const buildSearchParams = (searchParams: SearchParams) => { const data: any = []; const weightedParams: number[] = []; @@ -39,7 +36,7 @@ export const buildSearchParams = ( }); const params: any = { - output_fields: output_fields, + output_fields: searchParams.globalParams.output_fields, limit: searchParams.globalParams.topK, data: data, filter: searchParams.globalParams.filter, @@ -72,10 +69,9 @@ export const buildSearchParams = ( export const buildSearchCode = ( searchParams: SearchParams, - output_fields: string[], collection: CollectionFullObject ) => { - const params = buildSearchParams(searchParams, output_fields); + const params = buildSearchParams(searchParams); const isMultiple = params.data.length > 1; return {