找不到请求操作的编解码器:[map< varchar,int>< ->java.util.map];发行apache cassandra

dnph8jn4  于 2021-06-13  发布在  Cassandra
关注(0)|答案(1)|浏览(402)

我有一张有田地的table

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)
);

当我试图把它Map到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]

我该怎么解决?我读过关于编解码器的书,但我不太清楚

vaj7vani

vaj7vani1#

我用您的结构创建了一个表,并用示例数据填充它:

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中的对象Map器,工作代码如下。
类别声明:

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)"
    }
}

main函数-它首先插入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)

完整的代码在我的存储库中。此解决方案的一个缺点是它基于java驱动程序3.x,后者是驱动程序的早期主要版本。如果您对它没有严格的要求,建议您使用最新的主要发行版-4.x,它同时适用于cassandra和dse,并具有许多新功能。
尽管新版本中的对象Map器的工作方式有所不同—使用的是编译注解,而不是运行时注解,因此代码看起来不同,我们需要以不同的方式配置编译过程,它可能比驱动程序3.x更复杂,但代码本身可能更简单(完整的代码在这里)。
我们需要定义数据类(实体):

@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("")
}

用2个操作定义dao接口( insert 以及 findByCategory ):

@Dao
interface AppCategoryAggDao {
    @Insert
    fun insert(appCatAgg: AppCategoryAggData)

    @Select
    fun findByCategory(appCat: String): AppCategoryAggData?
}

定义Map器以获取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()

相关问题