Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More preset automation & usability improvements #324

Merged
merged 4 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 39 additions & 6 deletions common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@ export const IMAGE_FIELD_PATTERN = `{{image_field}}`;
export const QUERY_TEXT_PATTERN = `{{query_text}}`;
export const QUERY_IMAGE_PATTERN = `{{query_image}}`;
export const MODEL_ID_PATTERN = `{{model_id}}`;
export const VECTOR = 'vector';
export const VECTOR_PATTERN = `{{${VECTOR}}}`;
export const VECTOR_TEMPLATE_PLACEHOLDER = `\$\{${VECTOR}\}`;
export const DEFAULT_K = 10;

export const FETCH_ALL_QUERY = {
query: {
Expand All @@ -180,10 +184,9 @@ export const KNN_QUERY = {
query: {
knn: {
[VECTOR_FIELD_PATTERN]: {
vector: `{{vector}}`,
vector: VECTOR_PATTERN,
k: DEFAULT_K,
},
k: 10,
model_id: MODEL_ID_PATTERN,
},
},
};
Expand All @@ -196,7 +199,7 @@ export const SEMANTIC_SEARCH_QUERY_NEURAL = {
[VECTOR_FIELD_PATTERN]: {
query_text: QUERY_TEXT_PATTERN,
model_id: MODEL_ID_PATTERN,
k: 100,
k: DEFAULT_K,
},
},
},
Expand All @@ -211,7 +214,7 @@ export const MULTIMODAL_SEARCH_QUERY_NEURAL = {
query_text: QUERY_TEXT_PATTERN,
query_image: QUERY_IMAGE_PATTERN,
model_id: MODEL_ID_PATTERN,
k: 100,
k: DEFAULT_K,
},
},
},
Expand All @@ -234,6 +237,32 @@ export const MULTIMODAL_SEARCH_QUERY_BOOL = {
},
},
};
export const HYBRID_SEARCH_QUERY_MATCH_KNN = {
_source: {
excludes: [VECTOR_FIELD_PATTERN],
},
query: {
hybrid: {
queries: [
{
match: {
[TEXT_FIELD_PATTERN]: {
query: QUERY_TEXT_PATTERN,
},
},
},
{
knn: {
[VECTOR_FIELD_PATTERN]: {
vector: VECTOR_PATTERN,
k: DEFAULT_K,
},
},
},
],
},
},
};
export const HYBRID_SEARCH_QUERY_MATCH_NEURAL = {
_source: {
excludes: [VECTOR_FIELD_PATTERN],
Expand All @@ -253,7 +282,7 @@ export const HYBRID_SEARCH_QUERY_MATCH_NEURAL = {
[VECTOR_FIELD_PATTERN]: {
query_text: QUERY_TEXT_PATTERN,
model_id: MODEL_ID_PATTERN,
k: 5,
k: DEFAULT_K,
},
},
},
Expand Down Expand Up @@ -312,6 +341,10 @@ export const QUERY_PRESETS = [
name: `${WORKFLOW_TYPE.MULTIMODAL_SEARCH} (neural)`,
query: customStringify(MULTIMODAL_SEARCH_QUERY_NEURAL),
},
{
name: `Hybrid search (match & k-NN queries)`,
query: customStringify(HYBRID_SEARCH_QUERY_MATCH_KNN),
},
{
name: `Hybrid search (match & term queries)`,
query: customStringify(HYBRID_SEARCH_QUERY_MATCH_TERM),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,18 @@ export function SelectWithCustomOptions(props: SelectWithCustomOptionsProps) {
// selected option state
const [selectedOption, setSelectedOption] = useState<any[]>([]);

// update the selected option when the form is updated. set to empty if the form value is undefined
// or an empty string ('')
// update the selected option when the form is updated. if the form is empty,
// default to the top option. by default, this will re-trigger this hook with a populated
// value, to then finally update the displayed option.
useEffect(() => {
const formValue = getIn(values, props.fieldPath);
if (!isEmpty(formValue)) {
setSelectedOption([{ label: getIn(values, props.fieldPath) }]);
} else {
setSelectedOption([]);
if (props.options.length > 0) {
setFieldTouched(props.fieldPath, true);
setFieldValue(props.fieldPath, props.options[0].label);
}
}
}, [getIn(values, props.fieldPath)]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ import {
EuiFlexGroup,
EuiFlexItem,
EuiFormRow,
EuiSmallButton,
EuiSuperSelect,
EuiSuperSelectOption,
EuiText,
EuiTitle,
EuiSpacer,
} from '@elastic/eui';
import { SearchHit, WorkflowFormValues } from '../../../../../common';
import { JsonField } from '../input_fields';
Expand Down Expand Up @@ -142,41 +144,46 @@ export function ConfigureSearchRequest(props: ConfigureSearchRequestProps) {
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton
fill={false}
style={{ width: '100px' }}
size="s"
onClick={() => {
// for this test query, we don't want to involve any configured search pipelines, if any exist
// see https://opensearch.org/docs/latest/search-plugins/search-pipelines/using-search-pipeline/#disabling-the-default-pipeline-for-a-request
dispatch(
searchIndex({
apiBody: {
index: values.search.index.name,
body: values.search.request,
searchPipeline: '_none',
},
dataSourceId,
})
)
.unwrap()
.then(async (resp) => {
props.setQueryResponse(
JSON.stringify(
resp.hits.hits.map((hit: SearchHit) => hit._source),
undefined,
2
)
);
})
.catch((error: any) => {
props.setQueryResponse('');
console.error('Error running query: ', error);
});
}}
>
Test
</EuiButton>
<>
<EuiSmallButton
fill={false}
style={{ width: '100px' }}
onClick={() => {
// for this test query, we don't want to involve any configured search pipelines, if any exist
// see https://opensearch.org/docs/latest/search-plugins/search-pipelines/using-search-pipeline/#disabling-the-default-pipeline-for-a-request
dispatch(
searchIndex({
apiBody: {
index: values.search.index.name,
body: values.search.request,
searchPipeline: '_none',
},
dataSourceId,
})
)
.unwrap()
.then(async (resp) => {
props.setQueryResponse(
JSON.stringify(
resp.hits.hits.map((hit: SearchHit) => hit._source),
undefined,
2
)
);
})
.catch((error: any) => {
props.setQueryResponse('');
console.error('Error running query: ', error);
});
}}
>
Test
</EuiSmallButton>
<EuiSpacer size="s" />
<EuiText size="s" color="subdued">
Run query without any search pipeline configuration.
</EuiText>
</>
</EuiFlexItem>
</EuiFlexGroup>
</>
Expand Down
49 changes: 33 additions & 16 deletions public/pages/workflows/new_workflow/quick_configure_modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
MapFormValue,
QuickConfigureFields,
TEXT_FIELD_PATTERN,
VECTOR,
VECTOR_FIELD_PATTERN,
WORKFLOW_NAME_REGEXP,
WORKFLOW_TYPE,
Expand Down Expand Up @@ -172,8 +173,8 @@ function injectQuickConfigureFields(
workflow.ui_metadata.config,
quickConfigureFields
);
workflow.ui_metadata.config = updateSearchRequestConfig(
workflow.ui_metadata.config,
workflow.ui_metadata.config.search.request.value = injectPlaceholderValues(
(workflow.ui_metadata.config.search.request.value || '') as string,
quickConfigureFields
);
workflow.ui_metadata.config = updateSearchRequestProcessorConfig(
Expand Down Expand Up @@ -228,6 +229,7 @@ function updateIngestProcessorConfig(
}

// prefill ML search request processor config, if applicable
// including populating placeholders in any pre-configured query_template
function updateSearchRequestProcessorConfig(
config: WorkflowConfig,
fields: QuickConfigureFields
Expand All @@ -236,10 +238,28 @@ function updateSearchRequestProcessorConfig(
if (field.id === 'model' && fields.embeddingModelId) {
field.value = { id: fields.embeddingModelId };
}
if (field.id === 'input_map' || field.id === 'output_map') {
if (field.id === 'input_map') {
// TODO: pre-populate more if the query becomes standard
field.value = [[EMPTY_MAP_ENTRY]] as MapArrayFormValue;
}
if (field.id === 'output_map') {
// prepopulate 'vector' constant as the model output transformed field,
// so it is consistent and used in the downstream query_template, if configured.
field.value = [[{ key: VECTOR, value: '' }]] as MapArrayFormValue;
}
});
config.search.enrichRequest.processors[0].optionalFields = config.search.enrichRequest.processors[0].optionalFields?.map(
(optionalField) => {
let updatedOptionalField = optionalField;
if (optionalField.id === 'query_template') {
optionalField.value = injectPlaceholderValues(
(optionalField.value || '') as string,
fields
);
}
return updatedOptionalField;
}
);

return config;
}
Expand Down Expand Up @@ -295,39 +315,36 @@ function updateIndexConfig(
return config;
}

// pre-populate placeholders in the query, if applicable
function updateSearchRequestConfig(
config: WorkflowConfig,
// pre-populate placeholders for a query request string
function injectPlaceholderValues(
requestString: string,
fields: QuickConfigureFields
): WorkflowConfig {
): string {
let finalRequestString = requestString;
if (fields.embeddingModelId) {
config.search.request.value = ((config.search.request.value ||
'') as string).replace(
finalRequestString = finalRequestString.replace(
new RegExp(MODEL_ID_PATTERN, 'g'),
fields.embeddingModelId
);
}
if (fields.textField) {
config.search.request.value = ((config.search.request.value ||
'') as string).replace(
finalRequestString = finalRequestString.replace(
new RegExp(TEXT_FIELD_PATTERN, 'g'),
fields.textField
);
}
if (fields.vectorField) {
config.search.request.value = ((config.search.request.value ||
'') as string).replace(
finalRequestString = finalRequestString.replace(
new RegExp(VECTOR_FIELD_PATTERN, 'g'),
fields.vectorField
);
}
if (fields.imageField) {
config.search.request.value = ((config.search.request.value ||
'') as string).replace(
finalRequestString = finalRequestString.replace(
new RegExp(IMAGE_FIELD_PATTERN, 'g'),
fields.imageField
);
}

return config;
return finalRequestString;
}
Loading
Loading