Datastax java 驱动程序,将 scala 集合转换为 java 错误
Datastax java driver, convert scala collections to java error
我正在尝试将 Scala 映射(我正在尝试将其转换为 java.util.Map)存储到 cassandra 2.1.8 中。
数据结构如下所示:
Map[String -> Set[Tuple[String, String, String]]]
我创建了 table 如下:
CREATE TABLE mailing (emailaddr text PRIMARY KEY, totalmails bigint, emails map<text, frozen<set<tuple<text, text, text>>>>);
我首先尝试将集合转换为 java 集合:
def emailsToCassandra(addr: emailAddress, mail: MailContent, number: Int) = {
println("Inserting emails into cassandra")
mail.emails.foreach(result =>
setAsJavaSet(result._2)
)
然后我构建查询并尝试将地图转换为 java 地图:
val query = QueryBuilder.insertInto("emails", "mailing")
.value("emailAddr", addr.toString())
.value("totalmails", number)
.value("emails", mapAsJavaMap(mail.emails))
session.executeAsync(query)
我回来了:
java.lang.IllegalArgumentException: Value 1 of type class scala.collection.convert.Wrappers$MapWrapper does not correspond to any CQL3 type
我也试过这样做:
val lol = mail.emails.asInstanceOf[java.util.Map[String, java.util.Set[Tuple3[String, String, String]]]]
哪个没用
提前致谢
我远不是一个Scala专家,但是错误看起来像Scala "convertion" to Java Map的意思是把它封装成一个scala.collection.convert.Wrappers$MapWrapper 扩展了 java.util.AbstractMap,后者又实现了 java.util.Map。当 Cassandra 尝试将 Java 的类型映射到它自己的类型时,它不会遇到 MapWrapper 作为有效类型。
我建议您编写自己的方法,使用 Java 的等价物:HashMap 和 HashSet(耸肩)。此外,您应该对 TupleType 有疑问,因此在此转换期间您应该使用 Cassandra 的 TupleType。
这里有一些您需要克服的问题:
- 正在将地图转换为 java.util.Map 类型。 (您已经使用 mapAsJavaMap 涵盖了这一点)
- 将 Set[Tuple3] 转换为 java.util.Set 类型。
- 正在将 Tuple3 转换为 TupleValue。
不幸的是,驱动程序 (java.lang.IllegalArgumentException: Value 1 of type class scala.collection.convert.Wrappers$MapWrapper does not correspond to any CQL3 type
) 返回的错误具有误导性,因为 Map 类型在您的代码中正确转换,但 Tuple3 类型最终是它有问题的地方。我打开 JAVA-833 来跟踪这个。
我假设 MailContent 是什么,但这里有一些代码应该可以正常工作。完成繁重工作的主要逻辑是 emailsToCql
,它将 Tuple3[String, String, String]
映射到 TupleValue
,设置为 java.util.Set 并映射到 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("test@email.com", Map(
"dest@email.com" -> Set(("field1", "field2", "field3")),
"dest2@email.com" -> 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()
}
这会在 cqlsh 中生成如下所示的记录:
emailaddr | emails | totalmails
----------------+--------------------------------------------------------------------------------------------------------------+------------
test@email.com | {'dest2@email.com': {('2field1', '2field2', '2field3')}, 'dest@email.com': {('field1', 'field2', 'field3')}} | 2
user2244255 是对的,将它分离到它自己的方法中有助于我理解发生了什么。这是最终有效的代码:
def resultToJavaMap(mail: MailContent) ={
mapAsJavaMap(mail.emails.mapValues{result =>
setAsJavaSet(result.map {lol =>
val theType = TupleType.of(DataType.text(), DataType.text(), DataType.text())
val theValue = theType.newValue()
theValue.setString(0, lol.to.toString())
theValue.setString(1, lol.subject)
theValue.setString(2, lol.message)
})
})
本质上,您访问集合中的元组,将它们更改为 datastax 类型,然后将整个集合更改为 java.util.Set,然后将整个内容更改为 java.util.Map
我正在尝试将 Scala 映射(我正在尝试将其转换为 java.util.Map)存储到 cassandra 2.1.8 中。
数据结构如下所示:
Map[String -> Set[Tuple[String, String, String]]]
我创建了 table 如下:
CREATE TABLE mailing (emailaddr text PRIMARY KEY, totalmails bigint, emails map<text, frozen<set<tuple<text, text, text>>>>);
我首先尝试将集合转换为 java 集合:
def emailsToCassandra(addr: emailAddress, mail: MailContent, number: Int) = {
println("Inserting emails into cassandra")
mail.emails.foreach(result =>
setAsJavaSet(result._2)
)
然后我构建查询并尝试将地图转换为 java 地图:
val query = QueryBuilder.insertInto("emails", "mailing")
.value("emailAddr", addr.toString())
.value("totalmails", number)
.value("emails", mapAsJavaMap(mail.emails))
session.executeAsync(query)
我回来了:
java.lang.IllegalArgumentException: Value 1 of type class scala.collection.convert.Wrappers$MapWrapper does not correspond to any CQL3 type
我也试过这样做:
val lol = mail.emails.asInstanceOf[java.util.Map[String, java.util.Set[Tuple3[String, String, String]]]]
哪个没用
提前致谢
我远不是一个Scala专家,但是错误看起来像Scala "convertion" to Java Map的意思是把它封装成一个scala.collection.convert.Wrappers$MapWrapper 扩展了 java.util.AbstractMap,后者又实现了 java.util.Map。当 Cassandra 尝试将 Java 的类型映射到它自己的类型时,它不会遇到 MapWrapper 作为有效类型。
我建议您编写自己的方法,使用 Java 的等价物:HashMap 和 HashSet(耸肩)。此外,您应该对 TupleType 有疑问,因此在此转换期间您应该使用 Cassandra 的 TupleType。
这里有一些您需要克服的问题:
- 正在将地图转换为 java.util.Map 类型。 (您已经使用 mapAsJavaMap 涵盖了这一点)
- 将 Set[Tuple3] 转换为 java.util.Set 类型。
- 正在将 Tuple3 转换为 TupleValue。
不幸的是,驱动程序 (java.lang.IllegalArgumentException: Value 1 of type class scala.collection.convert.Wrappers$MapWrapper does not correspond to any CQL3 type
) 返回的错误具有误导性,因为 Map 类型在您的代码中正确转换,但 Tuple3 类型最终是它有问题的地方。我打开 JAVA-833 来跟踪这个。
我假设 MailContent 是什么,但这里有一些代码应该可以正常工作。完成繁重工作的主要逻辑是 emailsToCql
,它将 Tuple3[String, String, String]
映射到 TupleValue
,设置为 java.util.Set 并映射到 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("test@email.com", Map(
"dest@email.com" -> Set(("field1", "field2", "field3")),
"dest2@email.com" -> 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()
}
这会在 cqlsh 中生成如下所示的记录:
emailaddr | emails | totalmails
----------------+--------------------------------------------------------------------------------------------------------------+------------
test@email.com | {'dest2@email.com': {('2field1', '2field2', '2field3')}, 'dest@email.com': {('field1', 'field2', 'field3')}} | 2
user2244255 是对的,将它分离到它自己的方法中有助于我理解发生了什么。这是最终有效的代码:
def resultToJavaMap(mail: MailContent) ={
mapAsJavaMap(mail.emails.mapValues{result =>
setAsJavaSet(result.map {lol =>
val theType = TupleType.of(DataType.text(), DataType.text(), DataType.text())
val theValue = theType.newValue()
theValue.setString(0, lol.to.toString())
theValue.setString(1, lol.subject)
theValue.setString(2, lol.message)
})
})
本质上,您访问集合中的元组,将它们更改为 datastax 类型,然后将整个集合更改为 java.util.Set,然后将整个内容更改为 java.util.Map