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

Speed up MappingStats Computation on Coordinating Node #82830

Merged

Conversation

original-brownbear
Copy link
Member

@original-brownbear original-brownbear commented Jan 19, 2022

We can exploit the mapping deduplication logic to save deserializing the
same mapping repeatedly here. This should fix extremely long running
computations when the cache needs to be refreshed for these stats
in the common case of many duplicate mappings in a cluster.
Also, removed some confusing and needless set creation in the constructor here.

We could go even further here probably and merge the logic for analysis and mapping stats parsing into one, but it doesn't matter much. With this fix the time to get a response in a 10k indices cluster with many repeated but very large (Beats) mappings (as you would expect them to be in the real world) goes from ~10s down to sub-second in the uncached case.
This removes a very long running task from the management pool and also ensures we don't burn endless CPU responding to monitoring in clusters that go through frequent metadata updates and thus won't see all that much benefit from the caching in TransportClusterStatsAction.

relates #77466

@original-brownbear original-brownbear added >enhancement :Search Foundations/Mapping Index mappings, including merging and defining field types :Data Management/Stats Statistics tracking and retrieval APIs v8.1.0 labels Jan 19, 2022
@elasticmachine elasticmachine added Team:Search Meta label for search team Team:Data Management Meta label for data/management team labels Jan 19, 2022
@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-search (Team:Search)

@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-data-management (Team:Data Management)

Copy link
Contributor

@henningandersen henningandersen left a comment

Choose a reason for hiding this comment

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

Thanks @original-brownbear this is a nice optimization. I think our testing may be a bit thin towards this though, perhaps you can add a bit of randomized unittests for cases of shared and non-shared mappings for both analysis-stats and mapping-stats (or maybe I missed it, happy to be pointed to it instead).

@@ -51,30 +52,14 @@ public static AnalysisStats of(Metadata metadata, Runnable ensureNotCancelled) {
final Map<String, IndexFeatureStats> usedBuiltInTokenFilters = new HashMap<>();
final Map<String, IndexFeatureStats> usedBuiltInAnalyzers = new HashMap<>();

final Map<String, Integer> mappingCounts = Maps.newMapWithExpectedSize(metadata.getMappingsByHash().size());
Copy link
Contributor

Choose a reason for hiding this comment

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

I would find it more intuitive to use an IdentityHashMp or just a hash-map (since hash-code/equals compare on the hash anyway). Is there a reason to use an explicit hash-value as key here?

Copy link
Member Author

Choose a reason for hiding this comment

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

Right ... IdentityHashMap sounds nice and simplifies the loop a little as well saving another round of lookup :)

}
for (Map.Entry<String, Integer> mappingAndCount : mappingCounts.entrySet()) {
Set<String> indexAnalyzers = new HashSet<>();
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should also do ensureNotCancelled.run() here to ensure we can cancel here too.

Copy link
Member Author

Choose a reason for hiding this comment

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

++ adding it back

if (scriptSourceObject != null) {
String scriptSource = scriptSourceObject.toString();
int chars = scriptSource.length();
long lines = scriptSource.lines().count();
int docUsages = countOccurrences(scriptSource, DOC_PATTERN);
int sourceUsages = countOccurrences(scriptSource, SOURCE_PATTERN);
scriptStats.update(chars, lines, sourceUsages, docUsages);
for (int i = 0; i < multiplier; i++) {
scriptStats.update(chars, lines, sourceUsages, docUsages);
Copy link
Contributor

@henningandersen henningandersen Jan 22, 2022

Choose a reason for hiding this comment

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

I think we can add a multiplier param to FieldScriptStats.update too to avoid the loop?

Copy link
Member Author

Choose a reason for hiding this comment

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

++ that's cuter :)

@original-brownbear
Copy link
Member Author

Thanks for taking a look Henning!

perhaps you can add a bit of randomized unittests for cases of shared and non-shared mappings for both analysis-stats and mapping-stats

Right it was quite thin indeed. We had a pretty extensive test case for the mapping stats that I reused for a non-shard test (not the most beautiful solution but I figured it was a reasonable cost-return tradeoff).
For analyzer stats testing was quite thin, but the one test case I found I extended to cover the non-shared and shared case and it seems like that should logically cover all the things I could've broken.

Copy link
Contributor

@henningandersen henningandersen left a comment

Choose a reason for hiding this comment

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

LGTM, thanks for the extra work on the tests.

@@ -949,7 +949,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
return builder;
}

Map<String, MappingMetadata> getMappingsByHash() {
public Map<String, MappingMetadata> getMappingsByHash() {
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if we should just expose the size of the map, since that is all we need? Small point, but would be nice to keep this internal to this class.

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmm we could here but I have another PR inbound that needs this map. I left it as is for now, hope that's ok.

@elasticsearchmachine
Copy link
Collaborator

Hi @original-brownbear, I've created a changelog YAML for you.

@original-brownbear
Copy link
Member Author

@elasticmachine update branch

@elasticsearchmachine
Copy link
Collaborator

Hi @original-brownbear, I've created a changelog YAML for you.

@original-brownbear original-brownbear removed the :Search Foundations/Mapping Index mappings, including merging and defining field types label Jan 26, 2022
@elasticmachine elasticmachine removed the Team:Search Meta label for search team label Jan 26, 2022
@original-brownbear
Copy link
Member Author

@elasticmachine update branch (sorry some changelog madness here)

We can exploit the mapping deduplication logic to save deserializing the
same mapping repeatedly here. This should fix extremly long running
computations when the cache needs to be refreshed for these stats
in the common case of many duplicate mappings in a cluster.
In a follow-up we can probably do the same for `AnalysisStats` as well.
@elasticsearchmachine
Copy link
Collaborator

Hi @original-brownbear, I've created a changelog YAML for you.

@original-brownbear
Copy link
Member Author

Jenkins run elasticsearch-ci/part-2

@original-brownbear
Copy link
Member Author

Thanks Henning!

@original-brownbear original-brownbear merged commit f2cb910 into elastic:master Jan 26, 2022
@original-brownbear original-brownbear deleted the speed-up-mapping-stats branch January 26, 2022 13:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
:Data Management/Stats Statistics tracking and retrieval APIs >enhancement Team:Data Management Meta label for data/management team v8.1.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants