未找到请求操作的编解码器:[map<varchar, int> <-> java.util.Map];发布 Apache Cassandra
Posted
技术标签:
【中文标题】未找到请求操作的编解码器:[map<varchar, int> <-> java.util.Map];发布 Apache Cassandra【英文标题】:Codec not found for requested operation: [map<varchar, int> <-> java.util.Map]; issue Apache Cassandra 【发布时间】:2020-10-22 22:03:36 【问题描述】:我有一个包含字段的表格
CREATE TABLE app_category_agg (
category text,
app_count int,
sp_count int,
subscriber_count int,
window_revenue bigint,
top_apps frozen <list<map<text,int>>>,
PRIMARY KEY (category)
);
当我尝试将其映射到 kotlin 模型时
@Table("app_category_agg")
class AppCategoryAggData
@PrimaryKeyColumn(name = "category", ordinal = 0, type = PrimaryKeyType.PARTITIONED)
lateinit var category: String
@Column("app_count")
var appCount: Int = 0
@Column("sp_count")
var spCount: Int = 0
@Column("subscriber_count")
var subscriberCount: Int = 0
@Column("window_revenue")
var windowRevenue: Long = 0
@Column("top_apps")
var topApps: List<Any> = arrayListOf()
interface AppCategoryAggRepository: CassandraRepository<AppCategoryAggData, String>
@Query(value = "SELECT * FROM analytics_info.app_category_agg")
fun findAllAppCategoryAggData(): List<AppCategoryAggData>
我收到此错误
Query; CQL [SELECT * FROM analytics_info.app_category_agg]; Codec not found for requested operation: [map<varchar, int> <-> java.util.Map]; nested exception is com.datastax.driver.core.exceptions.CodecNotFoundException: Codec not found for requested operation: [map<varchar, int> <-> java.util.Map]
我该如何解决?我读过有关制作编解码器的信息,但对我来说不是很清楚
【问题讨论】:
是 Spring Data cassandra,还是来自 Java 驱动程序的对象映射器?你用的是什么驱动版本?你能展示一下你是如何使用它的吗? 是的,它的春季数据。我还添加了模型和存储库文件 我不是 100% 确定,但是 Spring Data Cassandra 存在嵌套集合的问题... 能否提出解决方案?最好在 Cassandra 中使用用户定义的类型或定义 Typecodec 让我试试 Kotlin 和驱动 3.x...对象映射器也支持 Kotlin:docs.datastax.com/en/developer/java-driver/4.7/manual/mapper/…(虽然我没有尝试过) 【参考方案1】:我用你的结构创建了一个表,并用示例数据填充它:
insert into app_category_agg (category, app_count, sp_count, subscriber_count, window_revenue, top_apps)
values('test', 2, 1, 10, 100, ['t1':1, 't2':2]);
对于来自 Java 驱动程序 3 的对象映射器,工作代码如下。
类声明:
import com.datastax.driver.mapping.MappingManager
import com.datastax.driver.mapping.annotations.Column
import com.datastax.driver.mapping.annotations.PartitionKey
import com.datastax.driver.mapping.annotations.Table
@Table(keyspace = "test", name = "app_category_agg")
class AppCategoryAggData
@PartitionKey
lateinit var category: String
@Column(name = "app_count")
var appCount: Int = 0
@Column(name = "sp_count")
var spCount: Int = 0
@Column(name = "subscriber_count")
var subscriberCount: Int = 0
@Column(name = "window_revenue")
var windowRevenue: Long = 0
@Column(name = "top_apps")
var topApps: List<Map<String, Int>> = emptyList()
override fun toString(): String
return "AppCategoryAggData(category='$category', appCount=$appCount, spCount=$spCount, subscriberCount=$subscriberCount, windowRevenue=$windowRevenue, topApps=$topApps)"
主函数 - 它首先从 Kotlin 代码中插入数据,然后读取我预先插入的数据:
import com.datastax.driver.core.Cluster
object KtTestObjMapper
@JvmStatic
fun main(args: Array<String>)
val cluster = Cluster.builder()
.addContactPoint("10.101.34.176")
.build()
val session = cluster.connect()
val manager = MappingManager(session)
val mapper = manager.mapper(AppCategoryAggData::class.java)
val appObj = AppCategoryAggData()
appObj.category = "kotlin"
appObj.appCount = 5
appObj.spCount = 10
appObj.subscriberCount = 50
appObj.windowRevenue = 10000
appObj.topApps = listOf(mapOf("t2" to 2))
mapper.save(appObj)
val obj2 = mapper.get("test")
print("obj2=$obj2")
session.close()
cluster.close()
当我运行此代码时,我收到以下输出:
Object from =AppCategoryAggData(category='test', appCount=2, spCount=1, subscriberCount=10, windowRevenue=100, topApps=[t1=1, t2=2])
当我使用 cqlsh
从表中选择数据时,我看到 Kotlin 插入了数据:
cqlsh:test> SELECT * from app_category_agg ;
category | app_count | sp_count | subscriber_count | top_apps | window_revenue
----------+-----------+----------+------------------+----------------------+----------------
test | 2 | 1 | 10 | ['t1': 1, 't2': 2] | 100
kotlin | 5 | 10 | 50 | ['t2': 2] | 10000
(2 rows)
full code is in my repository。该解决方案的一个缺点是它基于 Java 驱动程序 3.x,这是该驱动程序的先前主要版本。如果您对它没有严格的要求,建议使用最新的主要版本 - 4.x,它同时适用于 Cassandra 和 DSE,并且有很多新功能。
虽然新版本中的对象映射器工作方式不同——而不是运行时注解,而是使用编译注解,所以代码看起来不同,我们需要configure compilation process differently和it could be more complicated compared to driver 3.x,但代码本身可以更简单(full code is here)。
我们需要定义数据类(entity):
@Entity
@CqlName("app_category_agg")
data class AppCategoryAggData(
@PartitionKey var category: String,
@CqlName("app_count") var appCount: Int? = null,
@CqlName("sp_count") var spCount: Int? = null,
@CqlName("subscriber_count") var subscriberCount: Int? = null,
@CqlName("window_revenue") var windowRevenue: Long? = null,
@CqlName("top_apps") var topApps: List<Map<String, Int>>? = null
)
constructor() : this("")
Define the DAO interface 有 2 个操作(insert
和 findByCategory
):
@Dao
interface AppCategoryAggDao
@Insert
fun insert(appCatAgg: AppCategoryAggData)
@Select
fun findByCategory(appCat: String): AppCategoryAggData?
Define the Mapper获取DAO:
@Mapper
interface AppCategoryMapper
@DaoFactory
fun appCategoryDao(@DaoKeyspace keyspace: CqlIdentifier?): AppCategoryAggDao?
并使用它:
object KtTestObjMapper
@JvmStatic
fun main(args: Array<String>)
val session = CqlSession.builder()
.addContactPoint(InetSocketAddress("10.101.34.176", 9042))
.build()
// get mapper - please note that we need to use AppCategoryMapperBuilder
// that is generated by annotation processor
val mapper: AppCategoryMapper = AppCategoryMapperBuilder(session).build()
val dao: AppCategoryAggDao? = mapper.appCategoryDao(CqlIdentifier.fromCql("test"))
val appObj = AppCategoryAggData("kotlin2",
10, 11, 12, 34,
listOf(mapOf("t2" to 2)))
dao?.insert(appObj)
val obj2 = dao?.findByCategory("test")
println("Object from =$obj2")
session.close()
相比Java的变化是我们需要使用生成的类AppCategoryMapperBuilder
来获取AppCategoryMapper
的实例:
val mapper: AppCategoryMapper = AppCategoryMapperBuilder(session).build()
【讨论】:
感谢您的回答,我在模式中使用用户定义类型作为快速修复,因此我可以重用现有代码。我也会试试这个。 我为 Java 驱动程序 4.x 的对象映射器添加了一个代码示例以上是关于未找到请求操作的编解码器:[map<varchar, int> <-> java.util.Map];发布 Apache Cassandra的主要内容,如果未能解决你的问题,请参考以下文章