Repository navigation
Catalog requests get slow with one contract definition per asset (30k assets → seconds per request) #6050
Replies: 1 comment 1 reply
General commentsdeclaring one Asset, one PolicyDefinition and one ContractDefinition for 30k data assets is an anti-pattern. no wonder it gets sluggish. no level of optimization will completely eradicate that. As you already stated, policies are loaded from the database, and a Indexing the ID selectors: if you are referring to the SQL schema, then this is a job for you as adopter. we don't (nor will we ever) publish a production-grade SQL schema, only the one we use for testing. You have to activate the DDL for it explicitly, at which point you are on your own. The reasoning is, that publishing the schema would require us to also publish migration scripts etc., and that gets complicated quickly, so we chose not to do it. Caching: there is no general approach to caching that will satisfy everyone, nor will everyone need it. So if you already have something, best keep it in your code base. RecommendationInstead of optimizing the code for what I think is an anti-pattern (very high amounts of assets), i would strongly urge you to reconsider you data architecture: you said you have lots of products, each with a different timing policy attached to it. I don't know exactly what the policy is, but lets say it's something like a "must only use in this time window", then this policy is un-enforcible anyways (how do you prove not to do something). If it's more like a "must have done X within time frame Y" then its a different story, but needing this different for every one of the 30k assets still sounds fishy to me. In many use cases similar to yours, we have suggested creating just one EDC asset - the retrieval API for all data products, with query parameters. Assuming any claims like "I did X in timeframe Y" is present as verifiable credential, it is checked and verified upon contract negotiation. Any client how has successfully negotiated a contract has already proven its claims, so the provider can just trust them. So later, on the API call, you can take that claim at face value. The decision, whether a user is able to retrieve an item is then made by the data plane, e.g. based on an authorization token that contains those claims. take this suggestion with a grain of salt, since i don't know your exact use case |
Uh oh!
There was an error while loading. Please reload this page.
Hi all,
we run EDC as the provider connector of a data marketplace, and with ~30k published datasets the catalog became the
slowest part of the connector by far. We found two hot spots in
control-plane-catalog(unchanged in v1.0.0-RC4),fixed them in an extension on our side, and would like to propose the fixes upstream. Before opening issues/PRs we'd
like to know whether the approach fits.
Our setup
Each data product becomes one asset, one policy definition and one contract definition. The contract
definition's
assetsSelectorishttps://w3id.org/edc/v0.0.1/ns/id = <assetId>, and the policy (used as access andcontract policy) carries per-product terms: an availability window (
dateTime gteq/lteq) and, for restrictedproducts, a tenant constraint.
Why not share contract definitions? The terms are different for each product, so the contract policy is
different, and with it the contract definition. Moving the dates out of the policy would remove them from the
agreement. As far as we can see this is a normal DSP shape (each dataset with its own offers), and #4971 looks like
the same cost with "a few thousand assets".
What we measured
One control plane on PostgreSQL, 30,000 assets / policy definitions / contract definitions, all accessible, DSP
2025-1 catalog requests. Warm timings, first request after boot in brackets:
limit=1limit=50limit=50,offset=15000limit=1000All three return the same JSON (same datasets, offers and order) apart from the random UUIDs in the catalog
@idandin the offer ids. We haven't measured (a) + (b) without the cache.
Where the time goes
PolicyDefinitionStore.findByIdper contract definition, on every request, inContractDefinitionResolverImpl.resolveFor.computeIfAbsentdeduplicates shared policies, but with distinct ones it is 30k queries per catalog or datasetrequest, even for
limit=1.assetsSelectoris tested against every asset inDatasetResolverImpl.toDataset,and pagination happens after that
(L84-L88),
so a page costs
assets scanned × definitionspredicates: 1.5M for the first page of 50, ~450M for the page atoffset 15000.
The proposal
ContractDefinitionResolverImpl: onePolicyDefinitionStore.findAllwith
id in [...](chunked) instead of onefindByIdper definition. No caching and no behaviour change; policiesare still evaluated on every request.
idselectors inDatasetResolverImpl: definitions whose selector is onlyid = X/id in [...]are looked up by asset id, everything else is tested per asset as today. Matches are sorted by their original
position, so the output doesn't change. This is what makes large and deep pages usable.
a TTL and invalidation on
ContractDefinitionEvent/PolicyDefinitionEvent. It brings requests under 100 ms, butwith several control-plane replicas a change made on another replica only shows after the TTL (negotiation always
reads the stores, so only the catalog is affected). Would something like this be welcome as an opt-in, or is it
better kept out of core?
We'd be happy to contribute (a) and (b) as PRs against
main, with tests. Feedback, or pointers if this is alreadybeing worked on, are very welcome.
Thanks!
All reactions