1

我在我的应用程序中实施 fts4 时遇到了一些困难。我的目标是使用最新的 jetpack 组件(包括 Room 数据库)完全在 Kotlin 中构建应用程序。但是,当我查看fts4的文档时,这些示例是用 Java 编写的!

除了相关类的 android 文档和fts3/4 的 sqlite 文档之外,我还搜索了一些不同的教程。值得注意的是,这篇博文和这些幻灯片。到目前为止,我能够找到的所有教程都是用 Java 编写的,并且依赖于数据库迁移来构建 fts^(见下文)所需的虚拟表。尽管如此,我还没有拼凑出一个可行的解决方案。

这是我的代码的最新迭代:

实体:


@Entity(tableName = "items")

data class Item(
    @PrimaryKey 
    @ColumnInfo(name = "rowid")
    val rowId: Int,
    val qualities: String,
    val itemId: String,
    val name: String,
    val description: String,
    val quantity: Int,
   
) {
    override fun toString() = name
}

FTS 实体:

@Entity(tableName = "items_fts")
@Fts4(contentEntity = Item::class, tokenizer = FtsOptions.TOKENIZER_PORTER)

data class ItemFTS(
    @PrimaryKey
    @ColumnInfo(name = "rowid")
    val id: Int,
    val qualities: String
) {
    override fun toString() = items
}

房间数据库:

@Database(entities = [Item::class, ItemFTS::class], version = 1, exportSchema = false)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
    abstract fun itemDao(): ItemDao

    companion object {

        // For Singleton instantiation
        @Volatile private var instance: AppDatabase? = null

        fun getInstance(context: Context): AppDatabase {
            return instance ?: synchronized(this) {
                instance ?: buildDatabase(context).also { instance = it }
            }
        }

        // Create and pre-populate the database.
        private fun buildDatabase(context: Context): AppDatabase {
            return Room.databaseBuilder(context, AppDatabase::class.java, DATABASE_NAME)
                .addCallback(object : RoomDatabase.Callback() {
                    override fun onCreate(db: SupportSQLiteDatabase) {
                        super.onCreate(db)
                        val request = OneTimeWorkRequestBuilder<SeedDatabaseWorker>().build()
                        WorkManager.getInstance().enqueue(request)
                    }
                })
// **I tried adding in migrations here based on the blog posts attached to this stack overflow 
// question but didn't seem to work, even when I incremented the database version.**
                .build()
        }
    }
}

种子数据库工作者:

class SeedDatabaseWorker(
    context: Context,
    workerParams: WorkerParameters
) : CoroutineWorker(context, workerParams) {

    private val TAG by lazy { SeedDatabaseWorker::class.java.simpleName }

    override suspend fun doWork(): Result = coroutineScope {

        try {
            applicationContext.assets.open(ITEM_DATA_FILENAME).use { inputStream ->
                JsonReader(inputStream.reader()).use { jsonReader ->
                    val itemType = object : TypeToken<List<Item>>() {}.type
                    val itemList: List<Item> = Gson().fromJson(jsonReader, itemType)

                    val database = AppDatabase.getInstance(applicationContext)
                    database.itemDao().insertAll(itemList)

                    Result.success()
                }
            }
        } catch (ex: Exception) {
            Log.e(TAG, "Error seeding database", ex)
            Result.failure()
        }
    }
}

项目 DAO:

@Dao
interface ItemDao {

    @Query("SELECT * FROM items ORDER BY name")
    fun getItems(): LiveData<List<Item>>

    @Query("SELECT * FROM items WHERE itemId = :itemId")
    fun getItem(itemId: String): LiveData<Item>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertAll(items: List<Item>)

    @Query("SELECT * FROM items WHERE rowid IN (SELECT rowid FROM items_fts WHERE qualities MATCH :query) ORDER BY name")
    fun searchItems(query: String): LiveData<List<Item>>
}

另外,如果您想知道,我确保将 % 查询注释更改为 *.

^(注意)这不是我有任何经验的事情,可能是我努力想出一个可行的解决方案的部分原因。我有点不清楚 Room 将在幕后做多少工作,以及在生成、填充、索引和一般管理 fts 方面我需要干预多少。以前我的解决方案使用了非 fts 搜索查询,除了查询本身之外不需要任何 SQL。我对 SQL 不是很熟悉,而且我真的不了解迁移如何工作的基础知识。是否可以先构建数据库,然后将其迁移到新版本,而无需先安装应用程序,然后在更新版本中迁移数据库?如果不是,并且需要迁移来创建虚拟 fts 表,你怎么可能发布一个准备好 fts 的新 android 应用程序?!我觉得我的知识存在一些巨大的漏洞,阻碍了我取得任何进展。任何好的建议或提出的解决方案将不胜感激!

4

0 回答 0