I am trying to store a Scala Map (that I'm trying to convert to a java.util.Map) into cassandra 2.1.8.
The data structure looks like this:
Map[String -> Set[Tuple[String, String, String]]]
I created the table as follows:
CREATE TABLE mailing (emailaddr text PRIMARY KEY, totalmails bigint, emails map<text, frozen<set<tuple<text, text, text>>>>);
I first try to convert the Set's to java Set's:
def emailsToCassandra(addr: emailAddress, mail: MailContent, number: Int) = {
println("Inserting emails into cassandra")
mail.emails.foreach(result =>
setAsJavaSet(result._2)
)
I then build the query and attempt to convert the Map to a java Map:
val query = QueryBuilder.insertInto("emails", "mailing")
.value("emailAddr", addr.toString())
.value("totalmails", number)
.value("emails", mapAsJavaMap(mail.emails))
session.executeAsync(query)
I get back:
java.lang.IllegalArgumentException: Value 1 of type class scala.collection.convert.Wrappers$MapWrapper does not correspond to any CQL3 type
I also tried to do this:
val lol = mail.emails.asInstanceOf[java.util.Map[String, java.util.Set[Tuple3[String, String, String]]]]
Which didn't work
Thank you in advance
There are a few things you are going to need to overcome here:
Unfortunately the error returned by the driver (java.lang.IllegalArgumentException: Value 1 of type class scala.collection.convert.Wrappers$MapWrapper does not correspond to any CQL3 type) is misleading, as the Map type is converting correctly in your code, but the Tuple3 type is ultimately what it is having problems with. I opened up JAVA-833 to track this.
I'm making assumptions about what MailContent is, but here is some code that should make things work. The main logic that does the heavy lifting is emailsToCql which maps Tuple3[String, String, String] into TupleValue, Set to java.util.Set and Map to java.util.Map.
import com.datastax.driver.core.{DataType, TupleType, Cluster}
import com.datastax.driver.core.querybuilder.QueryBuilder
import scala.collection.JavaConverters._
object Scratch extends App {
val cluster = Cluster.builder().addContactPoint("127.0.0.1").build()
val session = cluster.connect()
session.execute("create keyspace if not exists emails WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };")
session.execute("create table if not exists emails.mailing (emailaddr text PRIMARY KEY, totalmails bigint, emails map<text, frozen<set<tuple<text, text, text>>>>);")
val emailType = TupleType.of(DataType.text(), DataType.text(), DataType.text())
case class MailContent(addr: String, emails: Map[String, Set[Tuple3[String, String, String]]]) {
lazy val emailsToCql = emails.mapValues {
_.map(v => emailType.newValue(v._1, v._2, v._3)).asJava
}.asJava
}
val mailContent = MailContent("[email protected]", Map(
"[email protected]" -> Set(("field1", "field2", "field3")),
"[email protected]" -> Set(("2field1", "2field2", "2field3"))))
val query = QueryBuilder.insertInto("emails", "mailing")
.value("emailAddr", mailContent.addr)
.value("totalmails", mailContent.emails.size)
.value("emails", mailContent.emailsToCql)
session.execute(query)
cluster.close()
}
This yields a record that looks like the following in cqlsh:
emailaddr | emails | totalmails
----------------+--------------------------------------------------------------------------------------------------------------+------------
[email protected] | {'[email protected]': {('2field1', '2field2', '2field3')}, '[email protected]': {('field1', 'field2', 'field3')}} | 2
I am far from being a Scala expert, but the error looks like Scala "convertion" to Java Map means to encapsulate it into a scala.collection.convert.Wrappers$MapWrapper that extends java.util.AbstractMap which, in turn, implements java.util.Map. When Cassandra tries to map from Java's types to its own it doesn't encounter MapWrapper as a valid type.
I would recommend you to write your own method to convert the whole thing (MailContent, right?) from a Map[String -> Set[Tuple[String, String, String]]] to a similar structure using Java's equivalents: HashMap and HashSet (shrug). Also, you should have problems with the TupleType so you should use Cassandra's TupleType during this conversion.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With