Browse Source

Merge pull request #255 from zilliztech/search

Support cosine and range search
ryjiang 1 year ago
parent
commit
88c47edd5e

+ 3 - 2
client/src/components/customSnackBar/CustomSnackBar.tsx

@@ -19,7 +19,8 @@ const useStyles = makeStyles((theme: Theme) =>
   createStyles({
     root: {
       borderRadius: '4px',
-      maxWidth: '300px',
+      maxWidth: '50vh',
+      wordBreak: 'break-all'
     },
     topRight: {
       [theme.breakpoints.up('md')]: {
@@ -37,7 +38,7 @@ const CustomSnackBar: FC<CustomSnackBarType> = props => {
     vertical,
     horizontal,
     open,
-    autoHideDuration = 2000,
+    autoHideDuration = 2500,
     type,
     message,
     onClose,

+ 18 - 3
client/src/consts/Milvus.ts

@@ -6,6 +6,7 @@ export const MILVUS_URL =
 export enum METRIC_TYPES_VALUES {
   L2 = 'L2',
   IP = 'IP',
+  COSINE = 'COSINE',
   HAMMING = 'HAMMING',
   JACCARD = 'JACCARD',
   TANIMOTO = 'TANIMOTO',
@@ -22,6 +23,10 @@ export const METRIC_TYPES = [
     value: METRIC_TYPES_VALUES.IP,
     label: 'IP',
   },
+  {
+    value: METRIC_TYPES_VALUES.COSINE,
+    label: 'COSINE',
+  },
   {
     value: METRIC_TYPES_VALUES.SUBSTRUCTURE,
     label: 'SUBSTRUCTURE',
@@ -47,6 +52,7 @@ export const METRIC_TYPES = [
 export type MetricType =
   | 'L2'
   | 'IP'
+  | 'COSINE'
   | 'HAMMING'
   | 'SUBSTRUCTURE'
   | 'SUPERSTRUCTURE'
@@ -60,7 +66,9 @@ export type searchKeywordsType =
   | 'search_length'
   | 'round_decimal'
   | 'level'
-  | 'search_list';
+  | 'search_list'
+  | 'radius'
+  | 'range_filter';
 
 export type indexConfigType = {
   [x: string]: {
@@ -71,6 +79,10 @@ export type indexConfigType = {
 
 // index
 export const FLOAT_INDEX_CONFIG: indexConfigType = {
+  SCANN: {
+    create: ['nlist'],
+    search: ['nprobe'],
+  },
   IVF_FLAT: {
     create: ['nlist'],
     search: ['nprobe'],
@@ -159,6 +171,10 @@ export const METRIC_OPTIONS_MAP = {
       value: METRIC_TYPES_VALUES.IP,
       label: METRIC_TYPES_VALUES.IP,
     },
+    {
+      value: METRIC_TYPES_VALUES.COSINE,
+      label: METRIC_TYPES_VALUES.COSINE,
+    },
   ],
   [DataTypeEnum.BinaryVector]: [
     {
@@ -195,7 +211,7 @@ export const DEFAULT_METRIC_VALUE_MAP = {
 
 // search params default value map
 export const DEFAULT_SEARCH_PARAM_VALUE_MAP: {
-  [key in searchKeywordsType]: number;
+  [key in searchKeywordsType]?: number;
 } = {
   // range: [top_k, 32768]
   ef: 250,
@@ -205,7 +221,6 @@ export const DEFAULT_SEARCH_PARAM_VALUE_MAP: {
   search_k: 250,
   // range: [10, 300]
   search_length: 10,
-  round_decimal: -1,
   level: 1,
   search_list: 20,
 };

+ 1 - 1
client/src/context/Root.tsx

@@ -61,7 +61,7 @@ export const RootProvider = (props: { children: React.ReactNode }) => {
     message: '',
     vertical: 'top',
     horizontal: 'right',
-    autoHideDuration: 3000,
+    autoHideDuration: 1000,
   });
   const [dialog, setDialog] = useState<DialogType>(DefaultDialogConfigs);
   const [drawer, setDrawer]: any = useState({

+ 58 - 26
client/src/pages/search/SearchParams.tsx

@@ -66,14 +66,26 @@ const SearchParams: FC<SearchParamsProps> = ({
           'warning'
         );
     }
+
+    const commonParams: searchKeywordsType[] = [
+      'radius',
+      'range_filter',
+      'round_decimal',
+    ];
     return indexType !== '' && isSupportedType
-      ? [...INDEX_CONFIG[indexType].search, 'round_decimal']
-      : ['round_decimal'];
+      ? [...INDEX_CONFIG[indexType].search, ...commonParams]
+      : commonParams;
   }, [indexType, openSnackBar, warningTrans]);
 
   const handleInputChange = useCallback(
-    (key: string, value: number) => {
-      const form = { ...searchParamsForm, [key]: value };
+    (key: string, value: number | string) => {
+      let form = { ...searchParamsForm };
+      if (value === '') {
+        delete form[key];
+      } else {
+        form = { ...searchParamsForm, [key]: Number(value) };
+      }
+
       handleFormChange(form);
     },
     [handleFormChange, searchParamsForm]
@@ -92,6 +104,7 @@ const SearchParams: FC<SearchParamsProps> = ({
         value,
         handleChange,
         isInt = true,
+        required = true,
       } = params;
 
       // search_k range is special compared to others,need to be handled separately
@@ -108,22 +121,13 @@ const SearchParams: FC<SearchParamsProps> = ({
         variant: 'filled',
         type: 'number',
         value,
-        validations: [
-          {
-            rule: 'require',
-            errorText: warningTrans('required', { name: label }),
-          },
-        ],
+        validations: [],
       };
-      if (!isSearchK && min && max) {
+
+      if (required) {
         config.validations?.push({
-          rule: 'range',
-          errorText: warningTrans('range', { min, max }),
-          extraParam: {
-            min,
-            max,
-            type: 'number',
-          },
+          rule: 'require',
+          errorText: warningTrans('required', { name: label }),
         });
       }
 
@@ -168,14 +172,15 @@ const SearchParams: FC<SearchParamsProps> = ({
         [key in searchKeywordsType]: SearchParamInputConfig;
       } = {
         round_decimal: {
-          label: 'Round Decimals',
+          label: 'round',
           key: 'round_decimal',
           value: searchParamsForm['round_decimal'] || '',
           min: -1,
           max: 10,
           isInt: true,
+          required: false,
           handleChange: value => {
-            handleInputChange('round_decimal', Number(value));
+            handleInputChange('round_decimal', value);
           },
           className: classes.inlineInput,
         },
@@ -187,7 +192,33 @@ const SearchParams: FC<SearchParamsProps> = ({
           max: nlist,
           isInt: true,
           handleChange: value => {
-            handleInputChange('nprobe', Number(value));
+            handleInputChange('nprobe', value);
+          },
+          className: classes.inlineInput,
+        },
+        radius: {
+          label: 'radius',
+          key: 'radius',
+          value: searchParamsForm['radius'] || '',
+          min: 1,
+          max: 1024,
+          isInt: false,
+          required: false,
+          handleChange: value => {
+            handleInputChange('radius', value);
+          },
+          className: classes.inlineInput,
+        },
+        range_filter: {
+          label: 'range filter',
+          key: 'range_filter',
+          value: searchParamsForm['range_filter'] || '',
+          min: 1,
+          max: 1024,
+          isInt: false,
+          required: false,
+          handleChange: value => {
+            handleInputChange('range_filter', value);
           },
           className: classes.inlineInput,
         },
@@ -199,7 +230,7 @@ const SearchParams: FC<SearchParamsProps> = ({
           max: 32768,
           isInt: true,
           handleChange: value => {
-            handleInputChange('ef', Number(value));
+            handleInputChange('ef', value);
           },
         },
         level: {
@@ -210,7 +241,7 @@ const SearchParams: FC<SearchParamsProps> = ({
           max: 3,
           isInt: true,
           handleChange: value => {
-            handleInputChange('level', Number(value));
+            handleInputChange('level', value);
           },
         },
         search_k: {
@@ -222,7 +253,7 @@ const SearchParams: FC<SearchParamsProps> = ({
           max: Infinity,
           isInt: true,
           handleChange: value => {
-            handleInputChange('search_k', Number(value));
+            handleInputChange('search_k', value);
           },
         },
         search_length: {
@@ -233,7 +264,7 @@ const SearchParams: FC<SearchParamsProps> = ({
           max: 300,
           isInt: true,
           handleChange: value => {
-            handleInputChange('search_length', Number(value));
+            handleInputChange('search_length', value);
           },
         },
         search_list: {
@@ -244,7 +275,7 @@ const SearchParams: FC<SearchParamsProps> = ({
           max: 65535,
           isInt: true,
           handleChange: value => {
-            handleInputChange('search_list', Number(value));
+            handleInputChange('search_list', value);
           },
         },
       };
@@ -294,6 +325,7 @@ const SearchParams: FC<SearchParamsProps> = ({
         label={indexTrans('metric')}
         wrapperClass={classes.selector}
         variant="filled"
+        disabled={true}
         onChange={(e: { target: { value: unknown } }) => {
           const metricType = e.target.value as string;
           handleMetricTypeChange(metricType);

+ 1 - 0
client/src/pages/search/Types.ts

@@ -52,6 +52,7 @@ export interface SearchParamInputConfig {
   value: number | string;
   handleChange: (value: number) => void;
   className?: string;
+  required?: boolean;
 }
 
 export interface VectorSearchParam {

+ 2 - 25
client/src/pages/search/VectorSearch.tsx

@@ -1,20 +1,9 @@
 import { useCallback, useEffect, useMemo, useState, useContext } from 'react';
-import {
-  Typography,
-  Button,
-  Card,
-  CardContent,
-  CardActionArea,
-} from '@material-ui/core';
+import { Typography, Button, Card, CardContent } from '@material-ui/core';
 import { useTranslation } from 'react-i18next';
 import { useLocation } from 'react-router-dom';
 import { ALL_ROUTER_TYPES } from '@/router/Types';
-import {
-  useNavigationHook,
-  useSearchResult,
-  usePaginationHook,
-  useTimeTravelHook,
-} from '@/hooks';
+import { useNavigationHook, useSearchResult, usePaginationHook } from '@/hooks';
 import { dataContext } from '@/context';
 import CustomSelector from '@/components/customSelector/CustomSelector';
 import { ColDefinitionsType } from '@/components/grid/Types';
@@ -26,7 +15,6 @@ import SimpleMenu from '@/components/menu/SimpleMenu';
 import { Option } from '@/components/customSelector/Types';
 import Filter from '@/components/advancedSearch';
 import { Field } from '@/components/advancedSearch/Types';
-import { CustomDatePicker } from '@/components/customDatePicker/CustomDatePicker';
 import { CollectionHttp, IndexHttp } from '@/http';
 import {
   parseValue,
@@ -99,9 +87,6 @@ const VectorSearch = () => {
     handleGridSort,
   } = usePaginationHook(searchResultMemo || []);
 
-  const { timeTravel, setTimeTravel, timeTravelInfo, handleDateTimeChange } =
-    useTimeTravelHook();
-
   const collectionOptions: Option[] = useMemo(
     () =>
       collections.map(c => ({
@@ -324,7 +309,6 @@ const VectorSearch = () => {
     setSearchResult(null);
     setFilterFields([]);
     setExpression('');
-    setTimeTravel(null);
   };
 
   const handleSearch = async (topK: number, expr = expression) => {
@@ -344,7 +328,6 @@ const VectorSearch = () => {
       search_params: searchParamPairs,
       vectors: [parseValue(vectors)],
       vector_type: fieldType,
-      travel_timestamp: timeTravelInfo.timestamp,
     };
 
     setTableLoading(true);
@@ -514,12 +497,6 @@ const VectorSearch = () => {
               filterDisabled={selectedField === '' || selectedCollection === ''}
               onSubmit={handleAdvancedFilterChange}
             />
-            <CustomDatePicker
-              label={timeTravelInfo.label}
-              onChange={handleDateTimeChange}
-              date={timeTravel}
-              setDate={setTimeTravel}
-            />
           </div>
           <div className="right">
             <CustomButton className="btn" onClick={handleReset}>

+ 4 - 0
client/src/utils/Form.ts

@@ -33,6 +33,10 @@ export const getMetricOptions = (
       value: METRIC_TYPES_VALUES.IP,
       label: 'IP',
     },
+    {
+      value: METRIC_TYPES_VALUES.COSINE,
+      label: 'COSINE',
+    },
   ];
 
   const baseBinaryOptions = [