Fix #10174: Display Synonym in the Glossary Term List and include Syn…onyms in Glossary Search; Fix #10738: Search Filters needs to be consistent across entities. Example Topic and Container; Fix #10789: Search experience: improve weight on direct match for tableName and columnName (#10807)

* Fix #10174: Display Synonym in the Glossary Term List and include Synonyms in Glossary Search; Fix #10738: Search Filters needs to be consistent across entities. Example Topic and Container; Fix #10789: Search experience: improve weight on direct match for tableName and columnName

* Fix #10174: Display Synonym in the Glossary Term List and include Synonyms in Glossary Search; Fix #10738: Search Filters needs to be consistent across entities. Example Topic and Container; Fix #10789: Search experience: improve weight on direct match for tableName and columnName

* Fix #10174: Display Synonym in the Glossary Term List and include Synonyms in Glossary Search; Fix #10738: Search Filters needs to be consistent across entities. Example Topic and Container; Fix #10789: Search experience: improve weight on direct match for tableName and columnName

* feat: implement filters for topic containers and glossary

* fix: jest tests

* fix: cypress tests

---------

Co-authored-by: karanh37 <karanh37@gmail.com>
Co-authored-by: karanh37 <33024356+karanh37@users.noreply.github.com>
This commit is contained in:
Sriharsha Chintalapani 2023-03-29 05:18:34 -07:00 committed by GitHub
parent e53a8c5859
commit 744cac26c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 240 additions and 34 deletions

View File

@ -51,8 +51,7 @@ public class TopicIndex implements ElasticSearchIndex {
doc.put("service_suggest", serviceSuggest);
doc.put("entityType", Entity.TOPIC);
doc.put("serviceType", topic.getServiceType());
doc.put("schemaText", topic.getMessageSchema() != null ? topic.getMessageSchema().getSchemaText() : null);
doc.put("schemaType", topic.getMessageSchema() != null ? topic.getMessageSchema().getSchemaType() : null);
doc.put("messageSchema", topic.getMessageSchema() != null ? topic.getMessageSchema() : null);
return doc;
}

View File

@ -415,7 +415,10 @@ public class SearchResource {
.field(FIELD_DISPLAY_NAME, 15.0f)
.field(FIELD_DISPLAY_NAME_NGRAM)
.field(FIELD_NAME, 15.0f)
.field(DISPLAY_NAME_KEYWORD, 25.0f)
.field(NAME_KEYWORD, 25.0f)
.field(FIELD_DESCRIPTION, 1.0f)
.field("columns.name.keyword", 10.0f)
.field("columns.name", 2.0f)
.field("columns.name.ngram")
.field("columns.displayName", 2.0f)
@ -466,6 +469,8 @@ public class SearchResource {
.field(FIELD_DISPLAY_NAME, 15.0f)
.field(FIELD_DISPLAY_NAME_NGRAM)
.field(FIELD_NAME, 15.0f)
.field(DISPLAY_NAME_KEYWORD, 25.0f)
.field(NAME_KEYWORD, 25.0f)
.field(FIELD_DESCRIPTION, 1.0f)
.field("messageSchema.schemaFields.name", 2.0f)
.field("messageSchema.schemaFields.description", 1.0f)
@ -493,6 +498,8 @@ public class SearchResource {
.field(FIELD_DISPLAY_NAME, 15.0f)
.field(FIELD_DISPLAY_NAME_NGRAM)
.field(FIELD_NAME, 15.0f)
.field(DISPLAY_NAME_KEYWORD, 25.0f)
.field(NAME_KEYWORD, 25.0f)
.field(FIELD_DESCRIPTION, 1.0f)
.field("charts.name", 2.0f)
.field("charts.description", 1.0f)
@ -523,6 +530,8 @@ public class SearchResource {
.field(FIELD_DISPLAY_NAME, 15.0f)
.field(FIELD_DISPLAY_NAME_NGRAM)
.field(FIELD_NAME, 15.0f)
.field(DISPLAY_NAME_KEYWORD, 25.0f)
.field(NAME_KEYWORD, 25.0f)
.field(DESCRIPTION, 1.0f)
.field("tasks.name", 2.0f)
.field("tasks.description", 1.0f)
@ -551,6 +560,8 @@ public class SearchResource {
.field(FIELD_DISPLAY_NAME, 15.0f)
.field(FIELD_DISPLAY_NAME_NGRAM)
.field(FIELD_NAME, 15.0f)
.field(DISPLAY_NAME_KEYWORD, 25.0f)
.field(NAME_KEYWORD, 25.0f)
.field(DESCRIPTION, 1.0f)
.field("mlFeatures.name", 2.0f)
.field("mlFeatures.description", 1.0f)
@ -580,7 +591,10 @@ public class SearchResource {
.field(FIELD_DISPLAY_NAME_NGRAM)
.field(FIELD_NAME, 15.0f)
.field(FIELD_DESCRIPTION, 1.0f)
.field(DISPLAY_NAME_KEYWORD, 25.0f)
.field(NAME_KEYWORD, 25.0f)
.field("dataModel.columns.name", 2.0f)
.field("dataModel.columns.name.keyword", 10.0f)
.field("dataModel.columns.name.ngram")
.field("dataModel.columns.displayName", 2.0f)
.field("dataModel.columns.displayName.ngram")
@ -686,7 +700,16 @@ public class SearchResource {
QueryStringQueryBuilder queryBuilder =
QueryBuilders.queryStringQuery(query)
.field(FIELD_NAME, 10.0f)
.field(NAME_KEYWORD, 10.0f)
.field(DISPLAY_NAME_KEYWORD, 10.0f)
.field(FIELD_DISPLAY_NAME, 10.0f)
.field(FIELD_DISPLAY_NAME_NGRAM)
.field("synonyms", 5.0f)
.field("synonyms.ngram")
.field(DESCRIPTION, 3.0f)
.field("glossary.name", 5.0f)
.field("glossary.displayName", 5.0f)
.field("glossary.displayName.ngram")
.defaultOperator(Operator.AND)
.fuzziness(Fuzziness.AUTO);
@ -699,8 +722,12 @@ public class SearchResource {
hb.field(highlightGlossaryName);
hb.preTags("<span class=\"text-highlighter\">");
hb.postTags("</span>");
return searchBuilder(queryBuilder, hb, from, size);
SearchSourceBuilder searchSourceBuilder =
new SearchSourceBuilder().query(queryBuilder).highlighter(hb).from(from).size(size);
searchSourceBuilder
.aggregation(AggregationBuilders.terms("tags.tagFQN").field("tags.tagFQN").size(MAX_AGGREGATE_SIZE))
.aggregation(AggregationBuilders.terms("glossary.name").field("glossary.name.keyword"));
return searchSourceBuilder;
}
private SearchSourceBuilder buildTagSearchBuilder(String query, int from, int size) {

View File

@ -17,6 +17,11 @@
"lowercase",
"om_stemmer"
]
},
"om_ngram": {
"tokenizer": "ngram",
"min_gram": 1,
"max_gram": 2
}
},
"filter": {
@ -47,10 +52,15 @@
},
"displayName": {
"type": "text",
"analyzer": "om_analyzer",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
},
"ngram": {
"type": "text",
"analyzer": "om_ngram"
}
}
},
@ -71,7 +81,17 @@
"type": "text"
},
"synonyms": {
"type": "text"
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
},
"ngram": {
"type": "text",
"analyzer": "om_ngram"
}
}
},
"glossary": {
"properties": {
@ -88,11 +108,29 @@
"type": "keyword"
},
"name": {
"type": "keyword",
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
},
"ngram": {
"type": "text",
"analyzer": "om_ngram"
}
}
},
"displayName": {
"type": "text",
"analyzer": "om_analyzer",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
},
"ngram": {
"type": "text",
"analyzer": "om_ngram"
}
}
},

View File

@ -76,11 +76,110 @@
"href": {
"type": "text"
},
"schemaText": {
"type": "text"
},
"schemaType": {
"type": "text"
"messageSchema": {
"properties": {
"schemaText": {
"type": "text"
},
"schemaType": {
"type": "text"
},
"schemaFields": {
"properties": {
"name": {
"type": "keyword",
"normalizer": "lowercase_normalizer",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"dataType": {
"type": "text"
},
"description": {
"type": "text",
"index_options": "docs",
"analyzer": "om_analyzer",
"norms": false
},
"fullyQualifiedName": {
"type": "text"
},
"tags": {
"properties": {
"tagFQN": {
"type": "keyword"
},
"labelType": {
"type": "keyword"
},
"description": {
"type": "text"
},
"source": {
"type": "keyword"
},
"state": {
"type": "keyword"
}
}
},
"children": {
"properties": {
"id": {
"type": "keyword",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 36
}
}
},
"type": {
"type": "keyword"
},
"name": {
"type": "keyword",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"fullyQualifiedName": {
"type": "text"
},
"description": {
"type": "text"
},
"tags": {
"properties": {
"tagFQN": {
"type": "keyword"
},
"labelType": {
"type": "keyword"
},
"description": {
"type": "text"
},
"source": {
"type": "keyword"
},
"state": {
"type": "keyword"
}
}
}
}
}
}
}
}
},
"cleanupPolicies": {
"type": "keyword"

View File

@ -70,7 +70,7 @@ describe('Tags page should work', () => {
cy.get('.ant-table-thead > tr > .ant-table-cell')
.eq(0)
.contains('Name')
.contains('Tag')
.should('be.visible');
cy.get('.ant-table-thead > tr > .ant-table-cell')
.eq(1)

View File

@ -19,6 +19,7 @@ import { Button, Card, Col, Row, Space, Tabs } from 'antd';
import FacetFilter from 'components/common/facetfilter/FacetFilter';
import SearchedData from 'components/searched-data/SearchedData';
import { SORT_ORDER } from 'enums/common.enum';
import { EntityType } from 'enums/entity.enum';
import unique from 'fork-ts-checker-webpack-plugin/lib/utils/array/unique';
import {
isEmpty,
@ -221,6 +222,10 @@ const Explore: React.FC<ExploreProps> = ({
});
};
const showFilters = useMemo(() => {
return entityDetails?.entityType !== EntityType.TAG ?? true;
}, [entityDetails]);
useEffect(() => {
const escapeKeyHandler = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
@ -323,14 +328,17 @@ const Explore: React.FC<ExploreProps> = ({
<Row gutter={[8, 0]} wrap={false}>
<Col className="searched-data-container" flex="auto">
<Row gutter={[16, 16]}>
<Col span={24}>
<ExploreQuickFilters
fields={selectedQuickFilters}
index={searchIndex}
onAdvanceSearch={() => toggleModal(true)}
onFieldValueSelect={handleQuickFiltersValueSelect}
/>
</Col>
{showFilters && (
<Col span={24}>
<ExploreQuickFilters
fields={selectedQuickFilters}
index={searchIndex}
onAdvanceSearch={() => toggleModal(true)}
onFieldValueSelect={handleQuickFiltersValueSelect}
/>
</Col>
)}
{sqlQuery && (
<Col span={24}>
<AppliedFilterText

View File

@ -305,7 +305,7 @@ const Appbar: React.FC = (): JSX.Element => {
});
} else {
// Outside Explore page
history.push(getExplorePath({ search: value }));
history.push(getExplorePath({ tab: 'tables', search: value }));
}
};

View File

@ -54,7 +54,7 @@ const FacetFilter: React.FC<FacetFilterProps> = ({
const sortedTiersList = {
...tier,
buckets: getSortedTierBucketList(tier.buckets),
buckets: tier ? getSortedTierBucketList(tier.buckets) : [],
};
return Object.entries({ ...restProps, 'tier.tagFQN': sortedTiersList })

View File

@ -21,6 +21,8 @@ const aggregationKeyToTitleMap: Record<string, string> = {
'tags.tagFQN': 'Tag',
'service.name.keyword': 'Service Name',
entityType: 'Entity Type',
'messageSchema.schemaFields.name': 'Schema Fields',
'glossary.name': 'Glossary',
};
const aggregationKeyOrdering: Record<string, number> = {

View File

@ -125,7 +125,7 @@ const NavBar = ({
{ value: SearchIndex.PIPELINE, label: t('label.pipeline') },
{ value: SearchIndex.MLMODEL, label: t('label.ml-model') },
{ value: SearchIndex.CONTAINER, label: t('label.container') },
{ value: SearchIndex.GLOSSARY, label: t('label.glossary-term') },
{ value: SearchIndex.GLOSSARY, label: t('label.glossary') },
{ value: SearchIndex.TAG, label: t('label.tag') },
],
[]
@ -142,6 +142,7 @@ const NavBar = ({
defaultActiveFirstOption
className="global-search-select"
listHeight={300}
popupClassName="global-search-select-menu"
value={searchCriteria}
onChange={updateSearchCriteria}>
{globalSearchOptions.map(({ value, label }) => (
@ -289,7 +290,7 @@ const NavBar = ({
to={{
pathname: ROUTES.TAGS,
}}>
{t('label.tag-plural')}
{t('label.classification')}
</NavLink>
),
},

View File

@ -74,6 +74,27 @@ export const PIPELINE_DROPDOWN_ITEMS = [
},
];
export const TOPIC_DROPDOWN_ITEMS = [
{
label: t('label.schema-field'),
key: 'messageSchema.schemaFields.name',
},
];
export const CONTAINER_DROPDOWN_ITEMS = [
{
label: t('label.column'),
key: 'dataModel.columns.name',
},
];
export const GLOSSARY_DROPDOWN_ITEMS = [
{
label: t('label.owner'),
key: 'owner.displayName',
},
];
export const ALL_DROPDOWN_ITEMS = [
...COMMON_DROPDOWN_ITEMS,
...TABLE_DROPDOWN_ITEMS,

View File

@ -97,7 +97,7 @@ export const tabsInfo: { [K in ExploreSearchIndex]: ExploreTabInfo } = {
path: 'containers',
},
[SearchIndex.GLOSSARY]: {
label: t('label.glossary-term-plural'),
label: t('label.glossary-plural'),
sortingFields: entitySortingFields,
sortField: INITIAL_SORT_FIELD,
path: 'glossary',

View File

@ -1145,7 +1145,7 @@
"schedule-for-ingestion-description": "Scheduling can be set up at an hourly, daily, or weekly cadence. The timezone is in UTC.",
"scheduled-run-every": "Scheduled to run every",
"scopes-comma-separated": "Add the Scopes value, separated by commas",
"search-for-entity-types": "Search for Tables, Topics, Dashboards, Pipelines and ML Models.",
"search-for-entity-types": "Search for Tables, Topics, Dashboards, Pipelines, ML Models, Glossary and Tags.",
"search-for-ingestion": "Search for ingestion",
"select-column-name": "Select column name",
"select-gcs-config-type": "Select GCS Config Type",

View File

@ -421,7 +421,7 @@ describe('Test TagsPage page', () => {
it('Table with respective header should be render', async () => {
const { container } = render(<TagsPage />);
const table = await findByTestId(container, 'table');
const name = await findByText(container, 'label.name');
const name = await findByText(container, 'label.tag');
const description = await findByText(container, 'label.description');
const actions = await findByText(container, 'label.action-plural');

View File

@ -722,7 +722,7 @@ const TagsPage = () => {
() =>
[
{
title: t('label.name'),
title: t('label.tag'),
dataIndex: 'name',
key: 'name',
render: (_, record: Tag) => getEntityName(record),
@ -918,8 +918,8 @@ const TagsPage = () => {
setIsAddingTag((prevState) => !prevState);
setErrorDataTag(undefined);
}}>
{t('label.add-new-entity', {
entity: t('label.tag-lowercase'),
{t('label.add-entity', {
entity: t('label.tag'),
})}
</Button>
</Tooltip>

View File

@ -23,3 +23,7 @@
}
}
}
.ant-tabs-tab + .ant-tabs-tab {
margin: 0 0 0 24px;
}

View File

@ -177,14 +177,14 @@ pre {
.search-grey::placeholder {
color: #6b7280;
}
.global-search-select {
width: 140px;
.global-search-select-menu {
width: 110px !important;
}
.appbar-search .rc-virtual-list-holder {
max-height: max-content;
}
.suggestions-menu {
margin-left: 140px;
margin-left: 60px;
}
/* Breadcrumb */

View File

@ -23,9 +23,12 @@ import { RenderSettings } from 'react-awesome-query-builder';
import {
ALL_DROPDOWN_ITEMS,
COMMON_DROPDOWN_ITEMS,
CONTAINER_DROPDOWN_ITEMS,
DASHBOARD_DROPDOWN_ITEMS,
GLOSSARY_DROPDOWN_ITEMS,
PIPELINE_DROPDOWN_ITEMS,
TABLE_DROPDOWN_ITEMS,
TOPIC_DROPDOWN_ITEMS,
} from '../constants/AdvancedSearch.constants';
import { AdvancedFields, EntityFields } from '../enums/AdvancedSearch.enum';
@ -40,7 +43,7 @@ export const getDropDownItems = (index: string) => {
return [...TABLE_DROPDOWN_ITEMS, ...COMMON_DROPDOWN_ITEMS];
case SearchIndex.TOPIC:
return [...COMMON_DROPDOWN_ITEMS];
return [...TOPIC_DROPDOWN_ITEMS, ...COMMON_DROPDOWN_ITEMS];
case SearchIndex.DASHBOARD:
return [...DASHBOARD_DROPDOWN_ITEMS, ...COMMON_DROPDOWN_ITEMS];
@ -52,6 +55,10 @@ export const getDropDownItems = (index: string) => {
return [
...COMMON_DROPDOWN_ITEMS.filter((item) => item.key !== 'service_type'),
];
case SearchIndex.CONTAINER:
return [...CONTAINER_DROPDOWN_ITEMS, ...COMMON_DROPDOWN_ITEMS];
case SearchIndex.GLOSSARY:
return [...GLOSSARY_DROPDOWN_ITEMS];
default:
return [];