Skip to content

Commit

Permalink
Support setup output fields on query page (#572)
Browse files Browse the repository at this point in the history
* support setup output fields for vector search

Signed-off-by: ryjiang <[email protected]>

* remove console

Signed-off-by: ryjiang <[email protected]>

* use same filter components for search and query page

Signed-off-by: ryjiang <[email protected]>

* support select output fields for query page

Signed-off-by: ryjiang <[email protected]>

* support dynamic fields selection

Signed-off-by: ryjiang <[email protected]>

* fix code block

Signed-off-by: ryjiang <[email protected]>

---------

Signed-off-by: ryjiang <[email protected]>
  • Loading branch information
shanghaikid authored Jul 11, 2024
1 parent 376f769 commit 8915b5d
Show file tree
Hide file tree
Showing 9 changed files with 169 additions and 99 deletions.
9 changes: 8 additions & 1 deletion client/src/hooks/Query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ export const useQuery = (params: {
const [total, setTotal] = useState<number>(collection.rowCount);
const [expr, setExpr] = useState<string>('');
const [queryResult, setQueryResult] = useState<any>({ data: [], latency: 0 });
const [outputFields, setOutputFields] = useState<string[]>(
fields.map(i => i.name) || []
);

// build local cache for pk ids
const pageCache = useRef(new Map());
Expand Down Expand Up @@ -76,7 +79,7 @@ export const useQuery = (params: {
try {
const queryParams = {
expr: _expr,
output_fields: fields.map(i => i.name),
output_fields: outputFields,
limit: pageSize || 10,
consistency_level,
// travel_timestamp: timeTravelInfo.timestamp,
Expand Down Expand Up @@ -181,5 +184,9 @@ export const useQuery = (params: {
count,
// get expression
getPageExpr,
// output fields
outputFields,
// set output fields
setOutputFields,
};
};
3 changes: 2 additions & 1 deletion client/src/i18n/cn/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ const collectionTrans = {
segmentsTab: '数据段(Segments)',
propertiesTab: '属性',
startTip: '开始你的数据查询',
exprPlaceHolder: '请输入你的数据查询,例如 id > 0',
exprPlaceHolder: '请输入你的查询表达式,例如 id > 0',
queryExpression: '查询表达式',

// alias dialog
aliasCreatePlaceholder: '别名',
Expand Down
3 changes: 2 additions & 1 deletion client/src/i18n/en/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ const collectionTrans = {
segmentsTab: 'Segments',
propertiesTab: 'Properties',
startTip: 'Start Your Data Query',
exprPlaceHolder: 'Please enter your data query, for example id > 0',
exprPlaceHolder: 'Please enter your query expression, eg: id > 0',
queryExpression: 'Query Expression',

// alias dialog
aliasCreatePlaceholder: 'Alias Name',
Expand Down
8 changes: 6 additions & 2 deletions client/src/pages/databases/Databases.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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,
{
Expand All @@ -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,
Expand Down
140 changes: 98 additions & 42 deletions client/src/pages/databases/collections/data/CollectionData.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useState, useEffect, useRef, useContext } from 'react';
import { TextField, Typography } from '@material-ui/core';
import { Typography } from '@material-ui/core';
import { useTranslation } from 'react-i18next';
import { rootContext, dataContext } from '@/context';
import { DataService } from '@/http';
Expand Down Expand Up @@ -27,6 +27,8 @@ import ImportSampleDialog from '@/pages/dialogs/ImportSampleDialog';
import { detectItemType } from '@/utils';
import { CollectionObject, CollectionFullObject } from '@server/types';
import StatusIcon, { LoadingType } from '@/components/status/StatusIcon';
import CustomInput from '@/components/customInput/CustomInput';
import CustomMultiSelector from '@/components/customSelector/CustomMultiSelector';

export interface CollectionDataProps {
collectionName: string;
Expand Down Expand Up @@ -144,6 +146,8 @@ const CollectionData = (props: CollectionDataProps) => {
query,
reset,
count,
outputFields,
setOutputFields,
} = useQuery({
collection,
consistencyLevel,
Expand Down Expand Up @@ -318,44 +322,51 @@ const CollectionData = (props: CollectionDataProps) => {
<CustomToolBar toolbarConfigs={toolbarConfigs} hideOnDisable={true} />
<div className={classes.toolbar}>
<div className="left">
<TextField
className="textarea"
value={expression}
onChange={(e: React.ChangeEvent<{ value: unknown }>) => {
setExpression(e.target.value as string);
}}
disabled={!collection.loaded}
InputLabelProps={{ shrink: true }}
label={expression ? ' ' : collectionTrans('exprPlaceHolder')}
onKeyDown={e => {
if (e.key === 'Enter') {
// reset page
setCurrentPage(0);
if (expr !== expression) {
setExpr(expression);
} else {
// ensure query
query();
<CustomInput
type="text"
textConfig={{
label: expression
? collectionTrans('queryExpression')
: collectionTrans('exprPlaceHolder'),
key: 'advFilter',
className: 'textarea',
onChange: (value: string) => {
setExpression(value);
},
value: expression,
disabled: !collection.loaded,
variant: 'filled',
required: false,
InputLabelProps: { shrink: true },
InputProps: {
endAdornment: (
<Filter
title={''}
showTitle={false}
fields={collection.schema.scalarFields}
filterDisabled={!collection.loaded}
onSubmit={handleFilterSubmit}
showTooltip={false}
/>
),
},
onKeyDown: (e: any) => {
if (e.key === 'Enter') {
// reset page
setCurrentPage(0);
if (expr !== expression) {
setExpr(expression);
} else {
// ensure query
query();
}
e.preventDefault();
}
e.preventDefault();
}
},
}}
inputRef={inputRef}
/>
<Filter
ref={filterRef}
title={btnTrans('advFilter')}
fields={collection.schema.fields.filter(
i =>
i.data_type !== DataTypeStringEnum.FloatVector &&
i.data_type !== DataTypeStringEnum.BinaryVector
)}
filterDisabled={!collection.loaded}
onSubmit={handleFilterSubmit}
showTitle={false}
showTooltip={false}
checkValid={() => true}
/>
{/* </div> */}

<CustomSelector
options={CONSISTENCY_LEVEL_OPTIONS}
value={consistencyLevel}
Expand All @@ -369,7 +380,55 @@ const CollectionData = (props: CollectionDataProps) => {
}}
/>
</div>

<div className="right">
<CustomMultiSelector
options={fields.map(f => {
return {
label:
f.name === DYNAMIC_FIELD
? searchTrans('dynamicFields')
: f.name,
value: f.name,
};
})}
values={outputFields}
renderValue={selected => (
<span>{`${(selected as string[]).length} ${
gridTrans[
(selected as string[]).length > 1 ? 'fields' : 'field'
]
}`}</span>
)}
label={searchTrans('outputFields')}
wrapperClass="selector"
variant="filled"
onChange={(e: { target: { value: unknown } }) => {
// add value to output fields if not exist, remove if exist
const newOutputFields = [...outputFields];
const values = e.target.value as string[];
const newFields = values.filter(
v => !newOutputFields.includes(v as string)
);
const removeFields = newOutputFields.filter(
v => !values.includes(v as string)
);
newOutputFields.push(...newFields);
removeFields.forEach(f => {
const index = newOutputFields.indexOf(f);
newOutputFields.splice(index, 1);
});

// sort output fields by schema order
newOutputFields.sort(
(a, b) =>
fields.findIndex(f => f.name === a) -
fields.findIndex(f => f.name === b)
);

setOutputFields(newOutputFields);
}}
/>
<CustomButton
className="btn"
onClick={handleFilterReset}
Expand Down Expand Up @@ -397,9 +456,9 @@ const CollectionData = (props: CollectionDataProps) => {
</div>
<AttuGrid
toolbarConfigs={[]}
colDefinitions={fields.map(i => {
colDefinitions={outputFields.map(i => {
return {
id: i.name,
id: i,
align: 'left',
disablePadding: false,
needCopy: true,
Expand All @@ -424,10 +483,7 @@ const CollectionData = (props: CollectionDataProps) => {
minWidth: getColumnWidth(d.field),
};
},
label:
i.name === DYNAMIC_FIELD
? searchTrans('dynamicFields')
: i.name,
label: i === DYNAMIC_FIELD ? searchTrans('dynamicFields') : i,
};
})}
primaryKey={collection.schema.primaryField.name}
Expand Down
5 changes: 4 additions & 1 deletion client/src/pages/databases/collections/data/Styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const getQueryStyles = makeStyles((theme: Theme) => ({
justifyContent: 'space-between',
alignItems: 'center',
flex: 1,
padding: theme.spacing(0, 0, 0, 2),
padding: theme.spacing(0, 0, 0, 0),
fontSize: theme.spacing(2),
backgroundColor: '#f4f4f4',

Expand All @@ -37,6 +37,9 @@ export const getQueryStyles = makeStyles((theme: Theme) => ({
},
'& .textarea': {
width: '100%',
'& .MuiFormHelperText-root': {
display: 'none',
},
},
},

Expand Down
44 changes: 17 additions & 27 deletions client/src/pages/databases/collections/search/Search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -179,7 +179,6 @@ const Search = (props: CollectionDataProps) => {

setTableLoading(false);
setSearchResult(res);
// setLatency(res.latency);
} catch (err) {
setTableLoading(false);
}
Expand All @@ -191,21 +190,6 @@ const Search = (props: CollectionDataProps) => {

let primaryKeyField = 'id';

const outputFields: string[] = useMemo(() => {
if (!searchParams || !searchParams.collection) {
return [];
}

const s = searchParams.collection.schema!;
const _outputFields = [...searchParams.globalParams.output_fields];

if (s.enable_dynamic_field) {
_outputFields.push(DYNAMIC_FIELD);
}

return _outputFields;
}, [JSON.stringify(searchParams)]);

const {
pageSize,
handlePageSize,
Expand All @@ -229,7 +213,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 &&
Expand Down Expand Up @@ -278,7 +271,11 @@ const Search = (props: CollectionDataProps) => {
};
})
: [];
}, [JSON.stringify({ searchParams, outputFields })]);
}, [
JSON.stringify({
searchParams,
}),
]);

// methods
const handlePageChange = (e: any, page: number) => {
Expand Down Expand Up @@ -410,10 +407,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 });
Expand Down Expand Up @@ -496,11 +490,7 @@ const Search = (props: CollectionDataProps) => {
params: {
component: (
<CodeDialog
data={buildSearchCode(
searchParams,
outputFields,
collection
)}
data={buildSearchCode(searchParams, collection)}
/>
),
},
Expand Down
Loading

0 comments on commit 8915b5d

Please sign in to comment.