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]

Reply via email to