Setting parameters in scala classes - scala

I am trying to get familiar with classes in Scala(spark) and I wrote a simple wrapper class over XGBoostClassifier to experiment with. Once that wrapper class was ready, I tried setting some parameters but I am getting errors and can't find much help online
This is the class I am using
class trialXGBClassifier{
var xgb_cls_object: XGBoostClassifier = _
}
I also wrote a small utility function to convert JSON to a Map (string, string)
def jsonToMap(jsonString: String): Map[String, String] = {
val jsonMap = JSON.parseFull(jsonString).get.asInstanceOf[Map[String, String]]
return jsonMap
}
And this is the code that's giving me the error
var params = """{"numRound": "10"}"""
var trial_xgb = new trialXGBClassifier
trial_xgb.xgb_cls_object.setSeed(jsonToMap(params)("numRound").toLong)
This is the error message I get
java.lang.NullPointerException
... 61 elided
I tried doing the following using the actual ml.dmlc class and it works
var xgb_orig = new XGBoostClassifier
xgb_orig.setSeed(jsonToMap(params)("numRound").toLong)
xgb_orig.getSeed #10
Whats the reason behind this error and how do I fix this?

In Scala, people try to use val instead of var in all places where such usage possible. Also, they try to use case class or sealed trait instead of just class.
So, there's a very nice way to avoid such kind of issues using case class:
case class TrialXGBClassifier(xgb_cls_object: XGBoostClassifier)
And then the best option to use your wrapper only when you have something to wrap:
val xgb_orig = new XGBoostClassifier
xgb_orig.setSeed(jsonToMap(params)("numRound").toLong)
val v = TrialXGBClassifier(xgb_orig)
And you even can omit xgb_orig declaration:
val v = TrialXGBClassifier(new XGBoostClassifier)
v.xgb_cls_object.setSeed(jsonToMap(params)("numRound").toLong)

Related

How to get a classOf[Array[T]] in Scala

I have a method (scala 2.12) that does look like the following.
The goal is to pass to the method readValue from objectMapper (jackson) a string and a class that the string needs to be casted, which in this case is an Array[T].
T can be two different case classes and therefore that is the reason of why I try to parametrize it.
private def fromSeqToCastedSeq[T](files: Seq[File]): Seq[T] = {
files flatMap (file => {
val maps = objectMapper.readValue(file, classOf[Map[String, Any]])
val combinedString = objectMapper.writeValueAsString(maps.get("sqlDefinitions"))
val o = objectMapper.readValue(combinedString, classOf[Array[T]])
o})
Currently this does not compile with a scala.MatchError because it is not able to cast it at runtime.
Could someone help me understand if what I'm trying to achieve is possible?
Thanks.
As answered in Discord, you should be able to do this:
import scala.reflect.ClassTag
private def fromSeqToCastedSeq[T](files: Seq[File])(implicit ct: ClassTag[T]): Seq[T] = {
val arrayTClass = ct.wrap.runtimeClass.asInstanceOf[Class[Array[T]]]
files.flatMap { file =>
val maps = objectMapper.readValue(file, classOf[Map[String, Any]])
val combinedString = objectMapper.writeValueAsString(maps.get("sqlDefinitions"))
objectMapper.readValue(combinedString, arrayTClass)
}
}
Now, no idea if this will crash at runtime, is highly probably given this piece of code is extremely unsafe and unidiomatic.

Transforming Scala case class into JSON

I have two case classes. The main one, Request, contains two maps.
The first map has a string for both key and value.
The second map has a string key, and value which is an instance of the second case class, KVMapList.
case class Request (var parameters:MutableMap[String, String] = MutableMap[String, String](), var deps:MutableMap[String, KVMapList] = MutableMap[String, KVMapList]())
case class KVMapList(kvMap:MutableMap[String, String], list:ListBuffer[MutableMap[String, String]])
The requirement is to transform Request into a JSON representation.
The following code is trying to do this:
import com.fasterxml.jackson.annotation.PropertyAccessor
import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility
import com.fasterxml.jackson.databind.ObjectMapper
def test(req:Request):String {
val mapper = new ObjectMapper() with ScalaObjectMapper
mapper.setVisibility(PropertyAccessor.ALL, Visibility.ANY)
var jsonInString: String = null
try {
jsonInString = mapper.writeValueAsString(request)
}
catch {
=case e: IOException => {
e.printStackTrace
}
jsonString
}
This however is not working. Even when the Request class is populated, the output is :
{"parameters":{"underlying":{"some-value":""},"empty":false,"traversableAgain":true},"deps":{"sizeMapDefined":false,"empty":false,"traversableAgain":true}}
Using the JSON object mapper with corresponding Java classes is straightforward, but have not yet got it working in Scala. Any assistance is very much appreciated.
Jackson is more of a bad old memory in Scala to some degree. You should use a native Scala library for JSON processing, particularly one really good at compile time derivation of JSON serializers, such as circe.
I'm aware this doesn't directly answer your question, but after using circe I would never go back to anything else.
import io.circe.generic.auto._
import io.circe.parser._
import io.circe.syntax._
val req = new Request(...)
val json = req.asJson.noSpaces
val reparsed = decode[Request](json)
On a different note, using mutable maps inside case classes is as non-idiomatic as it gets, and it should be quite trivial to implement immutable ops for your maps using the auto-generated copy method.
case class Request(parameters: Map[String, String] {
def +(key: String, value: String): Request = {
this.copy(parameters = parameters + (key -> value))
}
}
You should really avoid mutability wherever possible, and it looks like avoiding it here wouldn't be much work at all.
I am not sure what this ScalaObjectMapper does, doesn't look like it is useful.
If you add mapper.registerModule(DefaultScalaModule) in the beginning, it should work ... assuming that by MutableMap you mean mutable.Map, and not some sort of home-made class (because, if you do, you'd have to provide a serializer for it yourself).
(DefaultScalaModule is in jackson-module-scala library. Just add it to your build if you don't already have it).

Fail to use Manifest to to extract data with json4s

I have simple function that takes a string json and extract it to case class, it looks like this:
type ExtractionType
implicit def extractionManifest: Manifest[ExtractionType]
def myExctractionFunc: List[FinalModel] = {
val mylist: List[FinalType] = parse(response.body).extract[ExtractionType]
...
}
Now, theres are 2 services (in different classes) that are using this function and each one is implementing ExtractionType and extractionManifest differently.
BUT, for one service it works perfect, and for the other im getting the error:
The future returned an exception of type:
org.json4s.package$MappingException, with message: unknown error.
(myExctractionFunc is using futures and more complex stuff so I simplified it, this is why the error mention future)
the implementation of the service that fail to extract is:
case class Person (name: String, age: Int)
override type ExtractionType = List[Person]
override implicit val inManifest = Manifest.classType[List[Person]](classOf[List[Person]])
the service that succeed looks like this:
case class Animal(kindOfAnimal: String, age: Int)
case class JungleObjects(animals: List[Animal])
override type ExtractionType = JungleObjects
override implicit val inManifest = Manifest.classType[JungleObjects](classOf[JungleObjects])
does anyone can see why the one is working and the other is not?
I had to use all those case classes in my projects to separate things, I just simplified the code so the question won't be too annoying :)
thanks!

Task not serializable: java.io.NotSerializableException when calling function outside closure only on classes not objects

Getting strange behavior when calling function outside of a closure:
when function is in a object everything is working
when function is in a class get :
Task not serializable: java.io.NotSerializableException: testing
The problem is I need my code in a class and not an object. Any idea why this is happening? Is a Scala object serialized (default?)?
This is a working code example:
object working extends App {
val list = List(1,2,3)
val rddList = Spark.ctx.parallelize(list)
//calling function outside closure
val after = rddList.map(someFunc(_))
def someFunc(a:Int) = a+1
after.collect().map(println(_))
}
This is the non-working example :
object NOTworking extends App {
new testing().doIT
}
//adding extends Serializable wont help
class testing {
val list = List(1,2,3)
val rddList = Spark.ctx.parallelize(list)
def doIT = {
//again calling the fucntion someFunc
val after = rddList.map(someFunc(_))
//this will crash (spark lazy)
after.collect().map(println(_))
}
def someFunc(a:Int) = a+1
}
RDDs extend the Serialisable interface, so this is not what's causing your task to fail. Now this doesn't mean that you can serialise an RDD with Spark and avoid NotSerializableException
Spark is a distributed computing engine and its main abstraction is a resilient distributed dataset (RDD), which can be viewed as a distributed collection. Basically, RDD's elements are partitioned across the nodes of the cluster, but Spark abstracts this away from the user, letting the user interact with the RDD (collection) as if it were a local one.
Not to get into too many details, but when you run different transformations on a RDD (map, flatMap, filter and others), your transformation code (closure) is:
serialized on the driver node,
shipped to the appropriate nodes in the cluster,
deserialized,
and finally executed on the nodes
You can of course run this locally (as in your example), but all those phases (apart from shipping over network) still occur. [This lets you catch any bugs even before deploying to production]
What happens in your second case is that you are calling a method, defined in class testing from inside the map function. Spark sees that and since methods cannot be serialized on their own, Spark tries to serialize the whole testing class, so that the code will still work when executed in another JVM. You have two possibilities:
Either you make class testing serializable, so the whole class can be serialized by Spark:
import org.apache.spark.{SparkContext,SparkConf}
object Spark {
val ctx = new SparkContext(new SparkConf().setAppName("test").setMaster("local[*]"))
}
object NOTworking extends App {
new Test().doIT
}
class Test extends java.io.Serializable {
val rddList = Spark.ctx.parallelize(List(1,2,3))
def doIT() = {
val after = rddList.map(someFunc)
after.collect().foreach(println)
}
def someFunc(a: Int) = a + 1
}
or you make someFunc function instead of a method (functions are objects in Scala), so that Spark will be able to serialize it:
import org.apache.spark.{SparkContext,SparkConf}
object Spark {
val ctx = new SparkContext(new SparkConf().setAppName("test").setMaster("local[*]"))
}
object NOTworking extends App {
new Test().doIT
}
class Test {
val rddList = Spark.ctx.parallelize(List(1,2,3))
def doIT() = {
val after = rddList.map(someFunc)
after.collect().foreach(println)
}
val someFunc = (a: Int) => a + 1
}
Similar, but not the same problem with class serialization can be of interest to you and you can read on it in this Spark Summit 2013 presentation.
As a side note, you can rewrite rddList.map(someFunc(_)) to rddList.map(someFunc), they are exactly the same. Usually, the second is preferred as it's less verbose and cleaner to read.
EDIT (2015-03-15): SPARK-5307 introduced SerializationDebugger and Spark 1.3.0 is the first version to use it. It adds serialization path to a NotSerializableException. When a NotSerializableException is encountered, the debugger visits the object graph to find the path towards the object that cannot be serialized, and constructs information to help user to find the object.
In OP's case, this is what gets printed to stdout:
Serialization stack:
- object not serializable (class: testing, value: testing#2dfe2f00)
- field (class: testing$$anonfun$1, name: $outer, type: class testing)
- object (class testing$$anonfun$1, <function1>)
Grega's answer is great in explaining why the original code does not work and two ways to fix the issue. However, this solution is not very flexible; consider the case where your closure includes a method call on a non-Serializable class that you have no control over. You can neither add the Serializable tag to this class nor change the underlying implementation to change the method into a function.
Nilesh presents a great workaround for this, but the solution can be made both more concise and general:
def genMapper[A, B](f: A => B): A => B = {
val locker = com.twitter.chill.MeatLocker(f)
x => locker.get.apply(x)
}
This function-serializer can then be used to automatically wrap closures and method calls:
rdd map genMapper(someFunc)
This technique also has the benefit of not requiring the additional Shark dependencies in order to access KryoSerializationWrapper, since Twitter's Chill is already pulled in by core Spark
Complete talk fully explaining the problem, which proposes a great paradigm shifting way to avoid these serialization problems: https://github.com/samthebest/dump/blob/master/sams-scala-tutorial/serialization-exceptions-and-memory-leaks-no-ws.md
The top voted answer is basically suggesting throwing away an entire language feature - that is no longer using methods and only using functions. Indeed in functional programming methods in classes should be avoided, but turning them into functions isn't solving the design issue here (see above link).
As a quick fix in this particular situation you could just use the #transient annotation to tell it not to try to serialise the offending value (here, Spark.ctx is a custom class not Spark's one following OP's naming):
#transient
val rddList = Spark.ctx.parallelize(list)
You can also restructure code so that rddList lives somewhere else, but that is also nasty.
The Future is Probably Spores
In future Scala will include these things called "spores" that should allow us to fine grain control what does and does not exactly get pulled in by a closure. Furthermore this should turn all mistakes of accidentally pulling in non-serializable types (or any unwanted values) into compile errors rather than now which is horrible runtime exceptions / memory leaks.
http://docs.scala-lang.org/sips/pending/spores.html
A tip on Kryo serialization
When using kyro, make it so that registration is necessary, this will mean you get errors instead of memory leaks:
"Finally, I know that kryo has kryo.setRegistrationOptional(true) but I am having a very difficult time trying to figure out how to use it. When this option is turned on, kryo still seems to throw exceptions if I haven't registered classes."
Strategy for registering classes with kryo
Of course this only gives you type-level control not value-level control.
... more ideas to come.
I faced similar issue, and what I understand from Grega's answer is
object NOTworking extends App {
new testing().doIT
}
//adding extends Serializable wont help
class testing {
val list = List(1,2,3)
val rddList = Spark.ctx.parallelize(list)
def doIT = {
//again calling the fucntion someFunc
val after = rddList.map(someFunc(_))
//this will crash (spark lazy)
after.collect().map(println(_))
}
def someFunc(a:Int) = a+1
}
your doIT method is trying to serialize someFunc(_) method, but as method are not serializable, it tries to serialize class testing which is again not serializable.
So make your code work, you should define someFunc inside doIT method. For example:
def doIT = {
def someFunc(a:Int) = a+1
//function definition
}
val after = rddList.map(someFunc(_))
after.collect().map(println(_))
}
And if there are multiple functions coming into picture, then all those functions should be available to the parent context.
I solved this problem using a different approach. You simply need to serialize the objects before passing through the closure, and de-serialize afterwards. This approach just works, even if your classes aren't Serializable, because it uses Kryo behind the scenes. All you need is some curry. ;)
Here's an example of how I did it:
def genMapper(kryoWrapper: KryoSerializationWrapper[(Foo => Bar)])
(foo: Foo) : Bar = {
kryoWrapper.value.apply(foo)
}
val mapper = genMapper(KryoSerializationWrapper(new Blah(abc))) _
rdd.flatMap(mapper).collectAsMap()
object Blah(abc: ABC) extends (Foo => Bar) {
def apply(foo: Foo) : Bar = { //This is the real function }
}
Feel free to make Blah as complicated as you want, class, companion object, nested classes, references to multiple 3rd party libs.
KryoSerializationWrapper refers to: https://github.com/amplab/shark/blob/master/src/main/scala/shark/execution/serialization/KryoSerializationWrapper.scala
I'm not entirely certain that this applies to Scala but, in Java, I solved the NotSerializableException by refactoring my code so that the closure did not access a non-serializable final field.
Scala methods defined in a class are non-serializable, methods can be converted into functions to resolve serialization issue.
Method syntax
def func_name (x String) : String = {
...
return x
}
function syntax
val func_name = { (x String) =>
...
x
}
FYI in Spark 2.4 a lot of you will probably encounter this issue. Kryo serialization has gotten better but in many cases you cannot use spark.kryo.unsafe=true or the naive kryo serializer.
For a quick fix try changing the following in your Spark configuration
spark.kryo.unsafe="false"
OR
spark.serializer="org.apache.spark.serializer.JavaSerializer"
I modify custom RDD transformations that I encounter or personally write by using explicit broadcast variables and utilizing the new inbuilt twitter-chill api, converting them from rdd.map(row => to rdd.mapPartitions(partition => { functions.
Example
Old (not-great) Way
val sampleMap = Map("index1" -> 1234, "index2" -> 2345)
val outputRDD = rdd.map(row => {
val value = sampleMap.get(row._1)
value
})
Alternative (better) Way
import com.twitter.chill.MeatLocker
val sampleMap = Map("index1" -> 1234, "index2" -> 2345)
val brdSerSampleMap = spark.sparkContext.broadcast(MeatLocker(sampleMap))
rdd.mapPartitions(partition => {
val deSerSampleMap = brdSerSampleMap.value.get
partition.map(row => {
val value = sampleMap.get(row._1)
value
}).toIterator
})
This new way will only call the broadcast variable once per partition which is better. You will still need to use Java Serialization if you do not register classes.
I had a similar experience.
The error was triggered when I initialize a variable on the driver (master), but then tried to use it on one of the workers.
When that happens, Spark Streaming will try to serialize the object to send it over to the worker, and fail if the object is not serializable.
I solved the error by making the variable static.
Previous non-working code
private final PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
Working code
private static final PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
Credits:
https://learn.microsoft.com/en-us/answers/questions/35812/sparkexception-job-aborted-due-to-stage-failure-ta.html ( The answer of pradeepcheekatla-msft)
https://databricks.gitbooks.io/databricks-spark-knowledge-base/content/troubleshooting/javaionotserializableexception.html
def upper(name: String) : String = {
var uppper : String = name.toUpperCase()
uppper
}
val toUpperName = udf {(EmpName: String) => upper(EmpName)}
val emp_details = """[{"id": "1","name": "James Butt","country": "USA"},
{"id": "2", "name": "Josephine Darakjy","country": "USA"},
{"id": "3", "name": "Art Venere","country": "USA"},
{"id": "4", "name": "Lenna Paprocki","country": "USA"},
{"id": "5", "name": "Donette Foller","country": "USA"},
{"id": "6", "name": "Leota Dilliard","country": "USA"}]"""
val df_emp = spark.read.json(Seq(emp_details).toDS())
val df_name=df_emp.select($"id",$"name")
val df_upperName= df_name.withColumn("name",toUpperName($"name")).filter("id='5'")
display(df_upperName)
this will give error
org.apache.spark.SparkException: Task not serializable
at org.apache.spark.util.ClosureCleaner$.ensureSerializable(ClosureCleaner.scala:304)
Solution -
import java.io.Serializable;
object obj_upper extends Serializable {
def upper(name: String) : String =
{
var uppper : String = name.toUpperCase()
uppper
}
val toUpperName = udf {(EmpName: String) => upper(EmpName)}
}
val df_upperName=
df_name.withColumn("name",obj_upper.toUpperName($"name")).filter("id='5'")
display(df_upperName)
My solution was to add a compagnion class that handles all methods that are not seriazable within the class.

Scala: Update class field value

I have:
case class One(someParam: String) {
private val _defaultTimeout = readFromConfig("defaultTimeout")
val timeout: Timeout = akka.util.Timeout(_defaultTimeout seconds)
val info: Option[Info] = Await.result(someSmartService.getInformationForSomething(someParam)), timeout.duration)
}
I'm building a service, which will obscure (encrypt) some sensitive data. I'm doing it in a such way:
def encrypt(oldOne: One): One = {
val encryptedSomeParam = EncryptService.getHash(oldOne.someParam)
val encryptedInfo = encryptInfo(oldOne.info)
// what to do with that? ^^
one.copy(someParam = encryptedSomeParam)
}
Also, I need to encrypt some data inside this "info" field of class One. The issue is that it is a val and I cannot reassign the value of a val. Is there an easy way how to do that? For now I'm thinking about changing it to a var, but I think it's not the best way to do that. Also, I cannot write encrypted data to this value from the beginning like this:
val info: Option[Info] = EncryptionService.encrypt(someSmartService.getInformationForSomething(someParam))
As this field is used in other places where I need the fields to be not encrypted. I want to encrypt sensitive data before the persistence of the object to a database.
Any ideas?
Thanks in advance!
EDIT: I know, that this looks like a bad design, so if someone has a better idea how to deal with it I'm looking forward to hear from you :)
Why not make info a case class argument as well?
case class One(someParam: String, info: Option[Info])
You could implement a default value for info by defining the companion object like
object One {
def apply(someParam: String): One = One(someParam, someSmartService.getInformationForSomething(someParam))
}
That would allow you to work with Ones as follows:
One("foo")
One("foo", Some(...))
One(encryptedSomeParam, encryptedInfo)
One("plaintext").copy(someParam = encryptedSomeParam, info = encryptedInfo)
EDIT 1: Lazy info
Case classes cannot have lazy val arguments, i.e., neither info: => Option[String] nor lazy val info: Option[String] is allowed as an argument type.
You could make info a parameter-less function, though
case class One(someParam: String, info: () => Option[String])
object One {
def apply(someParam: String): One = One(someParam, () => Some(someParam))
}
and then use it as
One("hi", () => Some("foo"))
println(One("hi", () => None).info())
This is obviously not ideal since it is not possible to introduce these changes without breaking code client code. Better solutions are welcome.
EDIT 2: Lazy info, no case class
If you don't insist on One being a case class (for example, because you really need copy), you could use a regular class with lazy values and a companion object for easy use:
class One(_someParam: String, _info: => Option[String]) {
val someParam = _someParam
lazy val info = _info
}
object One {
def apply(someParam: String): One = new One(someParam, Await.result(...))
def apply(someParam: String, info: => Option[String]): One = new One(someParam, info)
def unapply(one: One) = Some((one.someParam, one.info))
}