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

Improve correlation by keeping arch info declared in manifest arp DisplayName entry #3100

Merged
merged 10 commits into from
Apr 6, 2023

Conversation

yao-msft
Copy link
Contributor

@yao-msft yao-msft commented Mar 23, 2023

Microsoft Reviewers: Open in CodeFlow
Microsoft Reviewers: Open in CodeFlow

@yao-msft yao-msft changed the title Improve correlation by using arch info if declared in manifest arp entry Improve correlation by keeping arch info declared in manifest arp DisplayName entry Mar 23, 2023

if (WI_IsFlagSet(fieldsToInclude, NormalizationField::Architecture) && m_arch != Utility::Architecture::Unknown)
{
result += '(' + std::string(Utility::ToString(m_arch)) + ')';
Copy link
Contributor

Choose a reason for hiding this comment

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

What about for packages that just include their architecture and not the parens? Or where it isn't just the arch to string? Won't this still cause issues? I feel like where DisplayName is included in the manifest, the normalization shouldn't occur.

  13  AppsAndFeaturesEntries:
  14:   - DisplayName: Bluebeam Revu x64 21
  34: - DisplayName: calibre 64bit
  35    UpgradeCode: '{5DD881FF-756B-4097-9D82-8C0F11D521EA}'
  23    - ProductCode: SyncBackPro64_is1_is1
  24:     DisplayName: SyncBackPro x64
  87:   - DisplayName: 7-Zip 22.01 (x64 edition)
  88      Publisher: Igor Pavlov
  28    - Publisher: Adobe
  29:     DisplayName: Adobe Acrobat DC (64-bit)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Our normalization code uses a regex which should take care of different formats of arch representations. x64, (x64), 64bit etc.

The reason we still need to do normalization on DisplayName comes from various considerations:

  1. Including every declared DisplayName explodes the index (which is currently around 13 mb), it will be at least several times bigger. Considering by default winget updates source every 3 mins if new version applicable, it's a lot of data downloading.
  2. If DisplayName contains version (or any other Package Version specific string) and we don't normalize it, our correlation will rely on the repo containing every version of the package (with every package version declaring DisplayName). For example, if DisplayName is Foo v1.0.0 and Foo v2.0.0 (2 versions exist in winget-pkgs repo), and if we don't normalize them in index, a local installed version with Foo v1.5.0 will not be able to get correlated. We cannot guarantee winget-pkgs will have every version of a package listed and client should not rely on this assumption.

According to our brief analysis, the arch is the main source of false correlation. And it makes sense to keep arch info specifically. We could expand to include locale, or even version if we decide to in the future. But each expansion will come with the cost of making index multiple times larger, and less correlation success if the installed version is not in the repo. Unless we redesign the index structure in future winget v2 (if winget v2 is a thing).

Copy link
Contributor

Choose a reason for hiding this comment

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

I see; thanks for the detailed explanation!

@github-actions

This comment has been minimized.

@yao-msft yao-msft marked this pull request as ready for review March 28, 2023 00:29
@yao-msft yao-msft requested a review from a team as a code owner March 28, 2023 00:29

PackageMatchFilter(PackageMatchField f, MatchType t) : RequestMatch(t), Field(f) { EnsureRequiredValues(); }
PackageMatchFilter(PackageMatchField f, MatchType t, Utility::NormalizedString& v) : RequestMatch(t, v), Field(f) { EnsureRequiredValues(); }
PackageMatchFilter(PackageMatchField f, MatchType t, const Utility::NormalizedString& v) : RequestMatch(t, v), Field(f) { EnsureRequiredValues(); }
PackageMatchFilter(PackageMatchField f, MatchType t, Utility::NormalizedString&& v) : RequestMatch(t, std::move(v)), Field(f) { EnsureRequiredValues(); }
PackageMatchFilter(PackageMatchField f, MatchType t, std::string_view v1, std::string_view v2) : RequestMatch(t, v1, v2), Field(f) { EnsureRequiredValues(); }
PackageMatchFilter(PackageMatchField f, MatchType t, std::string_view v1, std::string_view v2, Utility::NormalizationField n = Utility::NormalizationField::None) : RequestMatch(t, v1, v2), Field(f), NameNormalizationField(n) { EnsureRequiredValues(); }
Copy link
Member

Choose a reason for hiding this comment

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

The searching should not know or understand how normalization is being done.

void AddToFilters(std::vector<PackageMatchFilter>& filters) const
void AddToFilters(
std::vector<PackageMatchFilter>& filters,
Utility::NormalizationField nameNormalizationField = Utility::NormalizationField::None) const
Copy link
Member

Choose a reason for hiding this comment

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

I don't think that CompositeSource should need to be aware of this, other than potentially to be able to get the necessary data (names and publishers). But that is likely a separate issue that isn't directly related to this one; for instance, we probably aren't getting the full set of names and publishers from REST searches.

@@ -1054,14 +1099,17 @@ namespace AppInstaller::Repository
auto names = installedVersion->GetMultiProperty(PackageVersionMultiProperty::Name);
auto publishers = installedVersion->GetMultiProperty(PackageVersionMultiProperty::Publisher);

Utility::NameNormalizer normer(Utility::NormalizationVersion::Initial);
Copy link
Member

Choose a reason for hiding this comment

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

Different versions of the index will use different versions of the normalization; I don't think that this is future proof. The goal was that from the outside, normalization was known to be used, but not understood. I don't think that this level of detail is a workable solution for an arbitrary source to implement.

{
candidateSearches.emplace_back(installedPackageData.CreateInclusionsSearchRequest(Utility::NormalizationField::Architecture));
}
candidateSearches.emplace_back(installedPackageData.CreateInclusionsSearchRequest());
Copy link
Member

Choose a reason for hiding this comment

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

I don't really understand why we need to search for both in any scenario; it seems like it could lead to the same problem, just in the less likely reverse case. If winget-pkgs only had one architecture version, and we had the other installed, we would get a mismatch. The reason to leave the non-architectured index entry is for older clients.

If we find architecture, we should only search for the one with architecture. This does mean that we need to roll out the updated index before the updated client of course. This could be done by putting the search behavior behind an experimental feature for now, while leaving the index construction to include both. Once the index update is on the server, we can try it out with the experimental feature and then make it non-experimental if it is working.

Copy link
Member

Choose a reason for hiding this comment

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

I wonder if this is part of a larger problem where we are taking the first match rather than treating multiple matches as an issue (and thus resulting in no matches, with some logging of course).

Also, some analysis that I hadn't thought is to look at how many normalized name and publisher values (or any of the system reference string cohort) map onto multiple package ids. Any time that is happening is likely cause for concern.

Copy link
Contributor

@Trenly Trenly Mar 30, 2023

Choose a reason for hiding this comment

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

There's 153 unique norm_names that map to more than one package.

ID_Name_Map_DuplicatesOnly_2023-03-29.csv

If you look at the mapping where different package id's have duplicate name AND publisher, there's 339 id's that have duplication.

ID_Name_Publisher_Map_DuplicatesOnly_2023-03-29.csv

@@ -218,7 +224,7 @@ namespace AppInstaller::Repository::Microsoft::Schema::V1_2
if (filter.Field == PackageMatchField::NormalizedNameAndPublisher && filter.Type == MatchType::Exact)
{
Utility::NormalizedName normalized = m_normalizer.Normalize(Utility::FoldCase(filter.Value), Utility::FoldCase(filter.Additional.value()));
filter.Value = normalized.Name();
filter.Value = normalized.GetNormalizedName(filter.NameNormalizationField);
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 maybe we do need a new minor version so that we can always call GetNormalizedName with architecture.

@microsoft-github-policy-service microsoft-github-policy-service bot added the Needs-Author-Feedback Issue needs attention from issue or PR author label Mar 30, 2023
@yao-msft
Copy link
Contributor Author

After offline discussion, we will address above comments by moving all normalization related logic inside index search logic.
And add a new enum called SearchPurpose in search request, together with source type, SearchInternal can decide on the fallback logic if needed.

@microsoft-github-policy-service microsoft-github-policy-service bot added Needs-Attention Issue needs attention from Microsoft and removed Needs-Author-Feedback Issue needs attention from issue or PR author labels Mar 30, 2023
// Default search purpose.
Default,
// The result is used for correlation to an installed package.
CorrelationToInstalled,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

In the end I have to use 3 enums for search purpose because the sqlite index itself does not know if it's installed source, this info is only available at Source level

@yao-msft yao-msft merged commit 3165abe into microsoft:master Apr 6, 2023
@yao-msft yao-msft deleted the archmatch branch April 6, 2023 18:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs-Attention Issue needs attention from Microsoft
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants