Skip to content

add lazy data doc for comments#4793

Open
ppwadhwa wants to merge 3 commits into
holoviz:mainfrom
ppwadhwa:add_lazydata_doc
Open

add lazy data doc for comments#4793
ppwadhwa wants to merge 3 commits into
holoviz:mainfrom
ppwadhwa:add_lazydata_doc

Conversation

@ppwadhwa

Copy link
Copy Markdown
Collaborator

I have started a document for lazy data that @philippjfr and @jlstevens and I discussed awhile back. I included a cell with Philipp's notes on what to include. I think I need to include some examples, but I wanted to get feedback on what I have so far before I proceed.

@philippjfr

Copy link
Copy Markdown
Member

Great, will take a look!

@jlstevens

Copy link
Copy Markdown
Contributor

Thanks!

I'll take a closer look later but at first glance, this looks like a good summary of what 'lazy' means and what 'compute' and 'persist' are about. Of course a user guide will need to have some concrete, executable examples but this looks like a great start!

@jbednar jbednar left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Great progress, thanks!

"source": [
"### Lazy Data\n",
"\n",
"Lazy data, or lazy loading of data, is a technique used in which data is not actually loaded until it is needed. If used effectively, this allows for a more efficient use of system resources and performance. Additionally, a user can build up a list of tasks, or build a task graph, that uses the data, but doesn't actually run anything until told to do so. The *expression* is stored instead of the result.\n",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Maybe emphasize that lazy evaluation lets you separate describing what computations need to be done from actually doing them, and then have a bulleted or numbered list of why capturing such a pipeline lazily can be important:

  • Lets you select different compute engines at the point the computation is done (e.g. to parallelize the computation, run it on GPUs, run it on a remote server, etc.)
  • Lets you describe a series of operations where some of them might drastically reduce the size of the problem before computation begins, e.g. by sampling/selecting/slicing a large dataset for a case when only a small portion is actually used
  • Lets you run the operation "out of core", i.e., processing only a chunk at a time rather than loading all of the data at once, when the same operation must be done on many datapoints that together would not fit into memory

etc.

"cell_type": "markdown",
"metadata": {},
"source": [
"As explained here: https://holoviz.org/tutorial/Large_Data.html, HoloViews can accept Dask dataframes just as well as Pandas dataframes. It has the infostructure to accept the lazy data objects, and will evaluate the objects as needed in order to display the relevant information. \n",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think infostructure counts as jargon here, and should be replaced with a more specific description of what you mean. computational infrastructure?

"source": [
"### When would you want to use .persist() when using HoloViews?\n",
"\n",
"If you are going to be doing any computations before plotting (aggregating or reducing your data, for example), calling .persist() on these computations will avoid evaluating that portion of the task graph several times. These computations will be stored in memory on the cluster nodes, ready to be used when needed for your various plots. \n",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
"If you are going to be doing any computations before plotting (aggregating or reducing your data, for example), calling .persist() on these computations will avoid evaluating that portion of the task graph several times. These computations will be stored in memory on the cluster nodes, ready to be used when needed for your various plots. \n",
"If you are going to be doing any computations before plotting (aggregating or reducing your data, for example), calling .persist() on these computations will avoid evaluating that portion of the task graph repeatedly, e.g. as a user zooms or pans on the plot. These computations will be stored in memory on the cluster nodes, ready to be used when needed for your various plots. \n",

"\n",
"### When do you use .compute()? \n",
"\n",
"Some methods you may use will not support data being stored on multiple nodes. You may need to perform a sort on the entire dataset or get an index location with with `.iloc()`, and these require putting all the data on one node. In this case, it will be best to do as much as you can to reduce or aggregate your data on each node, and then use `.compute()` to bring everything to a single node. You can then use the methods that do not work across nodes to obtain your desired result. "

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd say something about ideally .compute() would return a reduced version of the original data -- aggregated, sliced, selected, etc., so that the resulting object is reasonable to fit in a single machine's memory even for a large distributed dataset.

@jlstevens

jlstevens commented Jan 19, 2021

Copy link
Copy Markdown
Contributor

One general thought, it might be worth giving a really basic and fundamental overview of what 'lazy' means. The easiest way to do this in Python is to compare lists to generators:

eager = [i for i in range(1000)] # versus
lazy = (i for i in range(1000000000000000000000000000000000)) # This is ok but don't try it in the list case!

@jbednar

jbednar commented Jan 19, 2021

Copy link
Copy Markdown
Member

Good point, but maybe use an example where the result could actually be used for something. E.g. an infinite generator for something like a Fibonacci sequence, but then you ask for the first 10 terms. Something lazy, followed by actually evaluating it for something reasonable, and pointing out that the eager version computes all 1000 then gives you the first 10, while the lazy one only ever does the first 10.

@jlstevens

jlstevens commented Jan 19, 2021

Copy link
Copy Markdown
Contributor

In that case you would use yield to explain laziness which is probably a good introduction at the Python level.

@ppwadhwa

ppwadhwa commented Mar 8, 2021

Copy link
Copy Markdown
Collaborator Author

@jbednar @jlstevens @philippjfr
I edited the text and added a couple of examples. Please take a look!
Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants