Github user squito commented on the pull request:
https://github.com/apache/spark/pull/5572#issuecomment-105269674
@viirya:
>> con: newly cached blocks, effectively adding some replication, but using
extra memory. Users will
>> most likely find that extra caching quite unexpected, and also won't
have any way to undo it.
> I agree that it uses extra memory. But as we only keep a copy of remote
block for all rdd1 partitions, it > might use less memory than just unrolling
the rdd2 partition in multiple tasks? As these remote blocks
> are cached with spark, I think user can using unpersist to explicitly
remove them too?
I *think* just calling `rdd2.unpersist()` (or `rdd1.unpersist()`) will
remove the newly cached blocks. But you are effectively adding full
replication, which is potentially a huge increase in the number of blocks
cached. Its very likely that each executor will store *all* of `rdd2` after
this. Eg., say you've got 100 partitions for `rdd2`, and you've got 100
executors, with each partition cached on a different executor. Then you'll
store each partition 100 times. Sure, a user *could* call `rdd2.unpersist()`,
but they would still not expect 100x replication _unless_ they call
`rdd2.unpersist()`, and furthermore they don't have a good way to go back to
just 1x replication, (except for unpersisting and re-persisting).
The more important thing to cache is probably `rdd2`. `rdd2.iterator` is
called once *per element* in `rdd1.iterator`, which is why you end up with
soooo many remote fetches in the current implementation. By caching `rdd1`
locally, you only save doing remote fetches for however many threads you have
in one executor. (And I'm not 100% sure that is even true as implemented in
the PR currently, I have a feeling all threads will simultaneously try to
fetch and insert into the local cache.) Most probably `elementsPerPartition >>
threadsPerExecutor`.
Can we step back a little and discuss your use case? Admittedly I never
user `cartesian` myself. I think of it as an *extremely* expensive operation
with very limited use case -- eg., both `rdd1` and `rdd2` need to be pretty
small. (this is also why I'm reluctant to make big changes for it.) I wonder
if you could do better by just changing your operations around a little. If
`rdd2` is tiny, maybe you'd be better off just `coalesce`ing it down to a very
small number of partitions first? Eg., do we just need better docs on
`cartesian` explaining its performance characteristics? But maybe you've got
some other use cases I'm not considering which help motivate this much better.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at [email protected] or file a JIRA ticket
with INFRA.
---
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]