Skip to content

Commit

Permalink
highlight matched fields in search results (#8651)
Browse files Browse the repository at this point in the history
  • Loading branch information
Joshua Eilers authored Aug 24, 2023
1 parent 6659ff2 commit a78e72c
Show file tree
Hide file tree
Showing 44 changed files with 840 additions and 375 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
import com.linkedin.datahub.graphql.generated.ListQueriesResult;
import com.linkedin.datahub.graphql.generated.ListTestsResult;
import com.linkedin.datahub.graphql.generated.ListViewsResult;
import com.linkedin.datahub.graphql.generated.MatchedField;
import com.linkedin.datahub.graphql.generated.MLFeature;
import com.linkedin.datahub.graphql.generated.MLFeatureProperties;
import com.linkedin.datahub.graphql.generated.MLFeatureTable;
Expand Down Expand Up @@ -1008,6 +1009,10 @@ private void configureGenericEntityResolvers(final RuntimeWiring.Builder builder
.dataFetcher("entity", new EntityTypeResolver(entityTypes,
(env) -> ((SearchResult) env.getSource()).getEntity()))
)
.type("MatchedField", typeWiring -> typeWiring
.dataFetcher("entity", new EntityTypeResolver(entityTypes,
(env) -> ((MatchedField) env.getSource()).getEntity()))
)
.type("SearchAcrossLineageResult", typeWiring -> typeWiring
.dataFetcher("entity", new EntityTypeResolver(entityTypes,
(env) -> ((SearchAcrossLineageResult) env.getSource()).getEntity()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import com.linkedin.datahub.graphql.generated.Privilege;
import com.linkedin.datahub.graphql.generated.QueriesTabConfig;
import com.linkedin.datahub.graphql.generated.ResourcePrivileges;
import com.linkedin.datahub.graphql.generated.SearchResultsVisualConfig;
import com.linkedin.datahub.graphql.generated.TelemetryConfig;
import com.linkedin.datahub.graphql.generated.TestsConfig;
import com.linkedin.datahub.graphql.generated.ViewsConfig;
Expand Down Expand Up @@ -144,6 +145,13 @@ public CompletableFuture<AppConfig> get(final DataFetchingEnvironment environmen
}
visualConfig.setEntityProfiles(entityProfilesConfig);
}
if (_visualConfiguration != null && _visualConfiguration.getSearchResult() != null) {
SearchResultsVisualConfig searchResultsVisualConfig = new SearchResultsVisualConfig();
if (_visualConfiguration.getSearchResult().getEnableNameHighlight() != null) {
searchResultsVisualConfig.setEnableNameHighlight(_visualConfiguration.getSearchResult().getEnableNameHighlight());
}
visualConfig.setSearchResult(searchResultsVisualConfig);
}
appConfig.setVisualConfig(visualConfig);

final TelemetryConfig telemetryConfig = new TelemetryConfig();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
package com.linkedin.datahub.graphql.types.mappers;

import com.linkedin.common.urn.Urn;
import com.linkedin.datahub.graphql.generated.AggregationMetadata;
import com.linkedin.datahub.graphql.generated.FacetMetadata;
import com.linkedin.datahub.graphql.generated.MatchedField;
import com.linkedin.datahub.graphql.generated.SearchResult;
import com.linkedin.datahub.graphql.resolvers.EntityTypeMapper;
import com.linkedin.datahub.graphql.types.common.mappers.UrnToEntityMapper;
import com.linkedin.metadata.search.SearchEntity;
import com.linkedin.metadata.search.utils.SearchUtils;
import lombok.extern.slf4j.Slf4j;

import java.net.URISyntaxException;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
Expand All @@ -16,6 +21,7 @@
import static com.linkedin.metadata.utils.SearchUtil.*;


@Slf4j
public class MapperUtils {

private MapperUtils() {
Expand Down Expand Up @@ -54,7 +60,20 @@ public static String convertFilterValue(String filterValue, List<Boolean> isEnti

public static List<MatchedField> getMatchedFieldEntry(List<com.linkedin.metadata.search.MatchedField> highlightMetadata) {
return highlightMetadata.stream()
.map(field -> new MatchedField(field.getName(), field.getValue()))
.map(field -> {
MatchedField matchedField = new MatchedField();
matchedField.setName(field.getName());
matchedField.setValue(field.getValue());
if (SearchUtils.isUrn(field.getValue())) {
try {
Urn urn = Urn.createFromString(field.getValue());
matchedField.setEntity(UrnToEntityMapper.map(urn));
} catch (URISyntaxException e) {
log.warn("Failed to create urn from MatchedField value: {}", field.getValue(), e);
}
}
return matchedField;
})
.collect(Collectors.toList());
}
}
15 changes: 15 additions & 0 deletions datahub-graphql-core/src/main/resources/app.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,11 @@ type VisualConfig {
Configuration for the queries tab
"""
entityProfiles: EntityProfilesConfig

"""
Configuration for search results
"""
searchResult: SearchResultsVisualConfig
}

"""
Expand Down Expand Up @@ -255,6 +260,16 @@ type EntityProfileConfig {
defaultTab: String
}

"""
Configuration for a search result
"""
type SearchResultsVisualConfig {
"""
Whether a search result should highlight the name/description if it was matched on those fields.
"""
enableNameHighlight: Boolean
}

"""
Configurations related to tracking users in the app
"""
Expand Down
5 changes: 5 additions & 0 deletions datahub-graphql-core/src/main/resources/search.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,11 @@ type MatchedField {
Value of the field that matched
"""
value: String!

"""
Entity if the value is an urn
"""
entity: Entity
}

"""
Expand Down
6 changes: 5 additions & 1 deletion datahub-web-react/src/app/entity/EntityRegistry.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React from 'react';
import { Entity as EntityInterface, EntityType, SearchResult } from '../../types.generated';
import { FetchedEntity } from '../lineage/types';
import { SearchResultProvider } from '../search/context/SearchResultContext';
import { Entity, EntityCapabilityType, IconStyleType, PreviewType } from './Entity';
import { GLOSSARY_ENTITY_TYPES } from './shared/constants';
import { GenericEntityProperties } from './shared/types';
Expand Down Expand Up @@ -119,7 +121,9 @@ export default class EntityRegistry {

renderSearchResult(type: EntityType, searchResult: SearchResult): JSX.Element {
const entity = validatedGet(type, this.entityTypeToEntity);
return entity.renderSearch(searchResult);
return (
<SearchResultProvider searchResult={searchResult}>{entity.renderSearch(searchResult)}</SearchResultProvider>
);
}

renderBrowse<T>(type: EntityType, data: T): JSX.Element {
Expand Down
9 changes: 7 additions & 2 deletions datahub-web-react/src/app/entity/chart/ChartEntity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@ import { EntityMenuItems } from '../shared/EntityDropdown/EntityDropdown';
import { LineageTab } from '../shared/tabs/Lineage/LineageTab';
import { ChartStatsSummarySubHeader } from './profile/stats/ChartStatsSummarySubHeader';
import { InputFieldsTab } from '../shared/tabs/Entity/InputFieldsTab';
import { ChartSnippet } from './ChartSnippet';
import { EmbedTab } from '../shared/tabs/Embed/EmbedTab';
import { capitalizeFirstLetterOnly } from '../../shared/textUtil';
import DataProductSection from '../shared/containers/profile/sidebar/DataProduct/DataProductSection';
import { getDataProduct } from '../shared/utils';
import EmbeddedProfile from '../shared/embed/EmbeddedProfile';
import { LOOKER_URN } from '../../ingest/source/builder/constants';
import { MatchedFieldList } from '../../search/matches/MatchedFieldList';
import { matchedInputFieldRenderer } from '../../search/matches/matchedInputFieldRenderer';

/**
* Definition of the DataHub Chart entity.
Expand Down Expand Up @@ -203,7 +204,11 @@ export class ChartEntity implements Entity<Chart> {
lastUpdatedMs={data.properties?.lastModified?.time}
createdMs={data.properties?.created?.time}
externalUrl={data.properties?.externalUrl}
snippet={<ChartSnippet matchedFields={result.matchedFields} inputFields={data.inputFields} />}
snippet={
<MatchedFieldList
customFieldRenderer={(matchedField) => matchedInputFieldRenderer(matchedField, data)}
/>
}
degree={(result as any).degree}
paths={(result as any).paths}
/>
Expand Down
53 changes: 0 additions & 53 deletions datahub-web-react/src/app/entity/chart/ChartSnippet.tsx

This file was deleted.

10 changes: 5 additions & 5 deletions datahub-web-react/src/app/entity/dashboard/DashboardEntity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,13 @@ import { EntityMenuItems } from '../shared/EntityDropdown/EntityDropdown';
import { LineageTab } from '../shared/tabs/Lineage/LineageTab';
import { capitalizeFirstLetterOnly } from '../../shared/textUtil';
import { DashboardStatsSummarySubHeader } from './profile/DashboardStatsSummarySubHeader';
import { ChartSnippet } from '../chart/ChartSnippet';
import { EmbedTab } from '../shared/tabs/Embed/EmbedTab';
import EmbeddedProfile from '../shared/embed/EmbeddedProfile';
import DataProductSection from '../shared/containers/profile/sidebar/DataProduct/DataProductSection';
import { getDataProduct } from '../shared/utils';
import { LOOKER_URN } from '../../ingest/source/builder/constants';
import { MatchedFieldList } from '../../search/matches/MatchedFieldList';
import { matchedInputFieldRenderer } from '../../search/matches/matchedInputFieldRenderer';

/**
* Definition of the DataHub Dashboard entity.
Expand Down Expand Up @@ -227,10 +228,9 @@ export class DashboardEntity implements Entity<Dashboard> {
lastUpdatedMs={data.properties?.lastModified?.time}
createdMs={data.properties?.created?.time}
snippet={
<ChartSnippet
isMatchingDashboard
matchedFields={result.matchedFields}
inputFields={data.inputFields}
<MatchedFieldList
customFieldRenderer={(matchedField) => matchedInputFieldRenderer(matchedField, data)}
matchSuffix="on a contained chart"
/>
}
subtype={data.subTypes?.typeNames?.[0]}
Expand Down
5 changes: 3 additions & 2 deletions datahub-web-react/src/app/entity/dataset/DatasetEntity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,12 @@ import { OperationsTab } from './profile/OperationsTab';
import { EntityMenuItems } from '../shared/EntityDropdown/EntityDropdown';
import { SidebarSiblingsSection } from '../shared/containers/profile/sidebar/SidebarSiblingsSection';
import { DatasetStatsSummarySubHeader } from './profile/stats/stats/DatasetStatsSummarySubHeader';
import { DatasetSearchSnippet } from './DatasetSearchSnippet';
import { MatchedFieldList } from '../../search/matches/MatchedFieldList';
import { EmbedTab } from '../shared/tabs/Embed/EmbedTab';
import EmbeddedProfile from '../shared/embed/EmbeddedProfile';
import DataProductSection from '../shared/containers/profile/sidebar/DataProduct/DataProductSection';
import { getDataProduct } from '../shared/utils';
import { matchedFieldPathsRenderer } from '../../search/matches/matchedFieldPathsRenderer';

const SUBTYPES = {
VIEW: 'view',
Expand Down Expand Up @@ -290,7 +291,7 @@ export class DatasetEntity implements Entity<Dataset> {
subtype={data.subTypes?.typeNames?.[0]}
container={data.container}
parentContainers={data.parentContainers}
snippet={<DatasetSearchSnippet matchedFields={result.matchedFields} />}
snippet={<MatchedFieldList customFieldRenderer={matchedFieldPathsRenderer} />}
insights={result.insights}
externalUrl={data.properties?.externalUrl}
statsSummary={data.statsSummary}
Expand Down
39 changes: 0 additions & 39 deletions datahub-web-react/src/app/entity/dataset/DatasetSearchSnippet.tsx

This file was deleted.

7 changes: 0 additions & 7 deletions datahub-web-react/src/app/entity/dataset/search/highlights.ts

This file was deleted.

38 changes: 0 additions & 38 deletions datahub-web-react/src/app/entity/dataset/shared/TagSummary.tsx

This file was deleted.

Loading

0 comments on commit a78e72c

Please sign in to comment.