Can I use Jupyter lab to interact with databricks spark cluster using Scala? - scala

Can I use Jupyter lab to connect to a databricks spark cluster that is hosted remotely?
There are KB articles about databricks connect, which allows a scala or java client-process to control a spark cluster. Here is an example:
https://docs.databricks.com/dev-tools/databricks-connect.html
While that KB article covers a lot of scenarios, it doesn't explain how to use Jupyter notebooks to interact with a databricks cluster using the Scala programming language. I'm familiar with scala programming, but not Python.

Yes, it appears to be possible although it is not well documented. These steps worked for me on windows. I used databricks v.7.1 with scala 2.12.10.
Step 1. Install anaconda : https://repo.anaconda.com/
Step 2. Because python seems to be the language of choice for notebooks,
you will need to manually install and configure a scala kernel
I'm able to get things working with the almond kernel : https://almond.sh/
When you install almond, be careful to pick a version of scala
that corresponds to the DBR runtime you will be connected to in the remote cluster.
Step 3. Now follow the databricks-connect docs to get a scala program to
compile and connect to the remote cluster via the intellij / sbt environment.
The documentation can be found here. https://docs.databricks.com/dev-tools/databricks-connect.html
This is a fully supported and fairly conventional approach that can be used to develop custom modules.
Step 4. Once you have created a working scala process, you will be familiar with sbt. The build.sbt is used for referencing the "databricks-connect" distribution. The distribution will be in a location like so:
unmanagedBase := new java.io.File("C:\\Users\\minime\\AppData\\Local\\Programs\\Python\\Python37\\Lib\\site-packages\\pyspark\\jars")
While it is straightforward for intellij / sbt to compile those dependencies into your program, it will take a bit more work to do the equivalent thing in he almond/jupyter kernel.
Before you go back to your jupyter notebook, run your new scala process and allow it to create a spark session. Then before the process dies, use "process explorer" to find the the related java.exe, then in the lower view/pane show handles, then copy all the handles into notepad (Ctrl+A in process explorer, Ctrl+V in notepad). This gives you the subset of modules from the databricks distribution that are actually being loaded into your process at runtime.
Step 5. Now that you have the relevant modules, you need to configure your almond scala kernel to load them into memory. Create a new jupyter notebook and select the scala kernel and use code like the following to load all your modules:
interp.load.cp(ammonite.ops.Path(java.nio.file.FileSystems.getDefault().getPath( "C:/Users/minime/AppData/Local/Programs/Python/Python37/Lib/site-packages/pyspark/jars/whatever001-1.1.1.jar")))
interp.load.cp(ammonite.ops.Path(java.nio.file.FileSystems.getDefault().getPath( "C:/Users/minime/AppData/Local/Programs/Python/Python37/Lib/site-packages/pyspark/jars/whatever002-1.1.1.jar")))
interp.load.cp(ammonite.ops.Path(java.nio.file.FileSystems.getDefault().getPath( "C:/Users/minime/AppData/Local/Programs/Python/Python37/Lib/site-packages/pyspark/jars/whatever003-1.1.1.jar")))
...
Please note that there are lots and lots of jars in the distribution (maybe 100!?).
You may wish to load other libraries directly from maven (assuming they are compatible with scala 2.12.10 and your databricks-connect distribution)
// Microsoft JDBC
interp.load.ivy("com.microsoft.sqlserver" % "mssql-jdbc" % "8.2.1.jre8")
// Other libraries
interp.load.ivy("joda-time" % "joda-time" % "2.10.5")
interp.load.ivy("org.scalaj" %% "scalaj-http" % "2.3.0")
interp.load.ivy("org.json4s" %% "json4s-native" % "3.5.3")
interp.load.ivy("com.microsoft.azure" % "msal4j" % "1.6.1")
// Other libraries
interp.load.ivy("org.apache.hadoop" % "hadoop-azure" % "3.2.1")
Fair warning... when loading libraries into the almond kernel, it is sometimes important to load them in a specific order. My examples above aren't intended to tell you what order to load them via interp.load.
Step 6. If everything went as planned, you should now be able to create a spark session running in a jupyter notebook using code that is similar to the stuff you were writing in "Step 3" above.
import org.apache.spark.sql._
val p_SparkSession = SparkSession.builder()
.appName("APP_" + java.util.UUID.randomUUID().toString)
.master("local")
.config("spark.cores.max","4")
.getOrCreate()
Your almond kernel is now connected to the remote cluster, via the databricks-connect distribution. Everything works as long as you don't need to serialize any functions or data types out to the remote cluster. In that case you will probably get a variety of serialization errors and null pointer exceptions. Here is an example:
java.lang.NullPointerException
com.databricks.service.SparkServiceClassSync$.checkSynced(SparkServiceClassSync.scala:244)
org.apache.spark.sql.util.SparkServiceObjectOutputStream.writeReplaceClassDescriptor(SparkServiceObjectOutputStream.scala:82)
...
org.apache.spark.sql.util.ProtoSerializer.serializePlan(ProtoSerializer.scala:377)
com.databricks.service.SparkServiceRPCClientStub.$anonfun$executePlan$1(SparkServiceRPCClientStub.scala:193)
This answer will be the first of several. I'm hoping that there are other scala/spark/databricks experts who can help work out the remaining kinks in this configuration, so that any of the functions and data types that are declared in my notebooks can be used by the remote cluster as well!

In my first answer I pointed out that the primary challenge in using scala notebooks (in Jupyter lab with almond) is that we are missing the functionality to serialize any functions or data types, and send them out to the remote cluster that is being hosted by databricks.
I should point out that there are two workarounds that I use regularly when I encounter this limitation.
I revert to using the "spark-shell". It is a standard component of the databricks-connect distribution. I can then load the relevant parts of my scala code using :load and :paste commands. For some happy reason the "spark-shell" is fully capable of serializing functions and data types in order to dynamically send them to the remote cluster. This is something that the almond kernel is not able to do for us within the context of the Jupyter notebooks.
The other workaround is to .collect() the dataframes back to the driver (within the memory of the jupyter notebook kernel.) Once they are collected, I can perform additional transformations on them, even with the help of "original" functions and "original" data types that are only found within my jupyter notebook. In this case I won't get the performance benefits of distributed processing. But while the code is still under development, I'm typically not working with very large datasets so it doesn't make that much of a difference if the driver is running my functions, or if the workers are.
Hope this is clear. I'm hoping that Databricks may eventually see the benefit of allowing scala programmers to develop code remotely, in jupyter lab. I think they need to be the ones to select one of the scala kernels, and do the heavy-lifting to support this scenario. As-of now they probably believe their own notebook experience in their own portal is sufficient for the needs of all scala programmers.

To add on to David's first answer, I did this additional step:
Step 5.5. Programmatically add the databricks jar dependencies to the scala kernel.
Using the directory you get from databricks-connect get-jar-dir I used the following code:
import $ivy.`com.lihaoyi::os-lib:0.2.7`
def importJars{
val myJars = os.list(os.Path("/Users/me/miniconda3/envs/dbx-p40/lib/python3.7/site-packages/pyspark/jars/"))
for (j <- myJars){
interp.load.cp(ammonite.ops.Path(java.nio.file.FileSystems.getDefault().getPath(j.toString)))
}
}
importJars

Related

Jupyter for Scala with spylon-kernel without having to install Spark

Based on web search and as highly recommended, I am trying to run Jupyter on my local for Scala (using spylon-kernel).
I was able to create a notebook but while trying to run/play a Scala code snippet, I see this message initializing scala interpreter and in the console, I see this error:
ValueError: Couldn't find Spark, make sure SPARK_HOME env is set or Spark is in an expected location (e.g. from homebrew installation).
I am not planning to install Spark. Is there a way I can still use Jupyter for Scala without installing Spark?
I am new to Jupyter and the ecosystem. Pardon me for the amateur question.
Thanks

How to use the Vegas visualization within a scala-spark jupyter notebook

When using the scala kernel with Vegas we see the nice charts
But when switching to the scala-spark kernel the imports no longer work:
What is the way to fix the imports for the spark kernel?
As described here you'll probably need to tweak your notebook config to pre-load those libraries, so they are available at runtime.
Then you can do a normal import (without the funny $ivy syntax, which actually comes from Ammonite REPL).

How to add external jar to Scala in Jupyter kernel

I would like to add the jar files from Stanford's CoreNLP into my Scala project. The part I'm struggling with in doing this in the context of a Scala kernel for Jupyter notebooks.
I'm using the Apachee Toree distribution for the kernel. There may be a simple one line command within-cell, but I can't find it.
Any help would be appreciated!
Not sure this applies to Stanford CoreNLP, but in a past project that involves evaluation of using IBM DSX on Jupytor Notebook, I read this article by Dustin V which consists of steps for adding jars. My guess is that the within-cell command you're seeking might be something similar to the following:
%AddJar http://nlp.stanford.edu/software/stanford-corenlp-models-current.jar -f

PySpark and PDB don't seem to mix

I'm building stand alone python programs that will use pyspark (and elasticsearch-hadoop connector). I am also addicted to the Python Debugger (PDB) and want to be able to step through my code.
It appears I can't run pyspark with the PDB like I normally do
./pyspark -m pdb testCode.py
I get an error "pyspark does not support any application options"
Is it possible to run pyspark code from the standard python interpreter? or do i need to give up the pdb?
I also saw online that I need to include py4j-0.9-src.zip in my PYTHONPATH. When I do that, I can use the python interpreter and step through my code, but I get an error "Py4JavaError: Py4JJava...t id=o18)" when it runs any of the pyspark code. That error seemed to indicate that I wasn't really interacting with spark.
How do I approach this?

Scala is a must for Spark?

I am new to Spark. In its docs, it says It is available in either Scala or Python.
And some blogs says spark depends on scala (for instance, http://cn.soulmachine.me/blog/20130614/). Therefore, I am wondering : Is scala a must for Spark? (Do I have to install scala first due to the dependency?)
The API of Scala has the following language bindings:
Scala
Java
Python
Scala as a natural fit, since it supports strongly functional programming, which is obvious benefical in the area of Big Data. Most tutorials and coding snippets, which you find on the net, are written in Scala.
Concerning the runtimne depenendencies please have a look at
the project download page
"Spark runs on Java 6+ and Python 2.6+. For the Scala API, Spark 1.2.0 uses Scala 2.10. You will need to use a compatible Scala version (2.10.x)."
Java is a must for Spark + many other transitive dependencies (scala compiler is just a library for JVM). PySpark just connects remotely (by socket) to the JVM using Py4J (Python-Java interoperation). Py4J is included in PySpark.
PySpark requires Python 2.6 or higher. PySpark applications are
executed using a standard CPython interpreter in order to support
Python modules that use C extensions. We have not tested PySpark with
Python 3 or with alternative Python interpreters, such as PyPy or
Jython.
All of PySpark’s library dependencies, including Py4J, are bundled
with PySpark and automatically imported.
Standalone PySpark applications should be run using the bin/pyspark
script, which automatically configures the Java and Python environment
using the settings in conf/spark-env.sh or .cmd. The script
automatically adds the bin/pyspark package to the PYTHONPATH.
https://spark.apache.org/docs/0.9.1/python-programming-guide.html - this instruction shows how to build and run all this with Scala/Java Build Tool (SBT), which will download all dependencies (including scala) automatically from remote repository. Yo can also use Maven.
If you don't want Java on your machine - you can start it on any other and configure PySpark for using it (by SparkConf().setMaster).
So, you need Java for master node with Spark itself (and all java-dependencies like scala), and Python 2.6 for py-client