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

[search ui] Add asset filter fields to search index #20372

Merged
merged 9 commits into from
Mar 12, 2024

Conversation

clairelin135
Copy link
Contributor

@clairelin135 clairelin135 commented Mar 8, 2024

This PR enables adds the following asset filters to the search index results:

  • asset owner
  • compute kind
  • code location
  • asset group

This involves:

  1. Querying for these fields per-asset on SECONDARY_SEARCH_QUERY
  2. Grouping by field to determine the # of assets per filter
  3. Adding each filter to the list of possible search results

Open questions:

  • Perf impact of fetching these additional fields for each asset in graphQL?

@clairelin135
Copy link
Contributor Author

clairelin135 commented Mar 8, 2024

Copy link

github-actions bot commented Mar 8, 2024

Deploy preview for dagit-core-storybook ready!

✅ Preview
https://dagit-core-storybook-9fgdh1fo4-elementl.vercel.app
https://03-07-claire-asset-search-ui.core-storybook.dagster-docs.io

Built with commit ed88cdc.
This pull request is being automatically deployed with vercel-action

@clairelin135 clairelin135 force-pushed the 03-07-claire/asset-search-ui branch 2 times, most recently from 1c9b8ca to 445969c Compare March 9, 2024 00:37
AssetGroup = 'AssetFilterSearchResultType.AssetGroup',
}

export function isAssetFilterSearchResultType(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure how to check if a value exists in a given enum... I was seeing the following always return true:

x: SearchResultType | AssetFilterSearchResultType = ...
x in AssetFilterSearchResultType // Returns true??

For now, just tested for strict equivalence to make this logic work

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checking the value against each enum member individually is fine, though I suspect that you won't need this function if the asset search UI is built separately from SearchDialog.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, thanks.

I think we still need this logic within the asset search component to render asset results and filter results a little differently.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved this function to the other PR where it's actually used

@clairelin135 clairelin135 marked this pull request as ready for review March 9, 2024 01:24
Copy link
Member

@hellendag hellendag left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some thoughts inline about separating the search components/hooks, related to comments on #20373.

Comment on lines 126 to 128
const searchAndHandleSecondary = React.useCallback(
async (queryString: string) => {
async (queryString: string, returnAssetFilters: boolean) => {
const {queryString: queryStringForResults, results} = await searchSecondary(queryString);
dispatch({type: 'complete-secondary', queryString: queryStringForResults, results});
if (!returnAssetFilters) {
dispatch({
type: 'complete-secondary',
queryString: queryStringForResults,
results: results.filter((result) => result.item.type === SearchResultType.Asset), // Only return asset results
});
} else {
dispatch({type: 'complete-secondary', queryString: queryStringForResults, results});
}
},
[searchSecondary],
);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's fine to add another parameter to configure what gets pushed to the worker, but here's a spot where I'd say that the behavior is specific to the search behavior itself, and not the component. I think you could pull this useCallback out into a hook that can be reused by SearchDialog and the new Asset UI. That way, SearchDialog never has to know about this behavior -- it can just skip the asset filters (by passing false to the hook, something like that) and otherwise remain unchanged.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explanation here.

I played around with pulling this callback out into a hook, though I realized after your other comment about avoiding building unwanted results that we could configure whether asset filters are returned at the useGlobalSearch hook level.

After that change, this filtering logic is no longer needed.

AssetGroup = 'AssetFilterSearchResultType.AssetGroup',
}

export function isAssetFilterSearchResultType(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checking the value against each enum member individually is fine, though I suspect that you won't need this function if the asset search UI is built separately from SearchDialog.

dispatch({
type: 'complete-secondary',
queryString: queryStringForResults,
results: results.filter((result) => result.item.type === SearchResultType.Asset), // Only return asset results
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like it would be a bit more efficient to avoid building the unwanted results, instead of discarding them here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, I implemented that within useGlobalSearch. A flag now is provided to useGlobalSearch to indicate whether asset filter results should be returned or not.

@clairelin135 clairelin135 force-pushed the 03-07-claire/asset-search-ui branch 3 times, most recently from 1010eea to ecffd16 Compare March 11, 2024 19:41
@clairelin135
Copy link
Contributor Author

@hellendag appreciate the explanations here.

I addressed the feedback and now SearchDialog doesn't need to know about asset filtering behavior, I think it's ready for another look!

Comment on lines 51 to 58
type AssetDefinitionMetadata = {
definition: {
owners: Array<
{__typename: 'UserAssetOwner'; email: string} | {__typename: 'TeamAssetOwner'; team: string}
>;
computeKind: string | null;
groupName: string | null;
repository: {
name: string;
location: {name: string};
};
} | null;
};

Copy link
Contributor

@salazarm salazarm Mar 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would go with something like this in order to keep a single source of truth for the base types.

type AssetDefinitionMetadata = {
  definition: Pick<AssetNode['definition'],  'owners' | ' computeKind' | 'groupName' | 'repository'>;
}

or if you don't like picking keys like that you could do

type AssetDefinitionMetadata = {
  definition: {
    owners: AssetNode['definition']['owners']
    ...
  },

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good call, I added this

@clairelin135 clairelin135 changed the base branch from master to 03-11-claire/allow-path-filter-by-owners March 11, 2024 23:33
@salazarm
Copy link
Contributor

One down side to this approach is that since there can be 2 instances of useGlobalSearch and they don't share cache with each other which means they will separately query the same data (via apollo so they should hit the shared cache if done one after the other, though it's possible both are open together in which case the cache isn't available so absent any apollo client query deduping it would be a duplicate request. afaik apollo doesnt dedupe).

@salazarm
Copy link
Contributor

I guess for now it's probably fine and we can optimize that later if it becomes a problem.

@clairelin135 clairelin135 force-pushed the 03-11-claire/allow-path-filter-by-owners branch from 2ed0ed1 to 9b8a2ec Compare March 12, 2024 18:42
// This is the version of the secondary query, used as part of the cache key.
// When the data in the cache must be invalidated, this version should be bumped to prevent
// fetching stale data.
export const SEARCH_SECONDARY_DATA_VERSION = 'v1;';
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We recently added caching to store the latest asset query result to load the search UI when the query hasn't completed. This PR adds additional fields to that query, but this causes an issue on the first load as the logic assumes those fields exist but they don't on the cached query data. This causes the asset search UI to be unloadable.

This PR adds a version to the key to ensure that we won't fetch stale data.

Base automatically changed from 03-11-claire/allow-path-filter-by-owners to master March 12, 2024 18:50
@@ -207,7 +297,7 @@ export const useGlobalSearch = () => {
loading: secondaryDataLoading,
} = useIndexedDBCachedQuery<SearchSecondaryQuery, SearchSecondaryQueryVariables>({
query: SEARCH_SECONDARY_QUERY,
key: 'SearchSecondary',
key: `SearchSecondary:${SEARCH_SECONDARY_DATA_VERSION}`,
Copy link
Contributor

@salazarm salazarm Mar 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works but it leaves the old cache in place so it never gets cleaned up. I think instead useIndexedDBCachedQuery should take a third parameter version that can be used to tell useIndexedDBCachedQuery to ignore caches on a different version.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. This PR is updated to now also store the data version in the cache.

I added a data version for both the primary and secondary queries since we should always be providing a version

Copy link
Contributor

@salazarm salazarm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sweet

@clairelin135 clairelin135 merged commit 2b3ed46 into master Mar 12, 2024
2 checks passed
@clairelin135 clairelin135 deleted the 03-07-claire/asset-search-ui branch March 12, 2024 21:31
jamiedemaria pushed a commit that referenced this pull request Mar 12, 2024
This PR enables adds the following asset filters to the search index
results:
- asset owner
- compute kind
- code location
- asset group

This involves:
1. Querying for these fields per-asset on `SECONDARY_SEARCH_QUERY`
2. Grouping by field to determine the # of assets per filter
3. Adding each filter to the list of possible search results

Open questions:
- Perf impact of fetching these additional fields for each asset in
graphQL?
PedramNavid pushed a commit that referenced this pull request Mar 28, 2024
This PR enables adds the following asset filters to the search index
results:
- asset owner
- compute kind
- code location
- asset group

This involves:
1. Querying for these fields per-asset on `SECONDARY_SEARCH_QUERY`
2. Grouping by field to determine the # of assets per filter
3. Adding each filter to the list of possible search results

Open questions:
- Perf impact of fetching these additional fields for each asset in
graphQL?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants