У меня возникли трудности с реализацией fts4 в мое приложение. Моя цель - создать приложение полностью на Kotlin, используя новейшие компоненты Jetpack, включая базу данных Room. Тем не менее, когда я посмотрел документацию для fts4, примеры были написаны на Java!
Кроме документации по android для связанных классов и документации sqlite для fts3 / 4 , Я просмотрел несколько разных уроков по этому вопросу. Примечательно, что этот блог пост и эти слайды . Все учебники, которые я смог найти до сих пор, были написаны на Java и основаны на миграциях баз данных для создания виртуальной таблицы, необходимой для fts ^ (СМ. НИЖЕ, НИЖЕ). Несмотря на это, мне еще предстоит собрать воедино рабочее решение.
Вот последняя итерация моего кода:
Entity:
@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:
@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>>
}
Кроме того, если вам интересно, Я позаботился о том, чтобы изменить аннотацию% query на *.
^ (ПРИМЕЧАНИЕ). У меня нет такого опыта, и это может быть одной из причин, почему я изо всех сил пытаюсь придуматьрабочий раствор. Мне немного неясно, сколько работы Room будет выполнять за кулисами, и сколько мне нужно вмешиваться, когда дело доходит до генерации, заполнения, индексации и общего управления fts-аспектами. Ранее мое решение использовало поисковый запрос не-fts, который не требовал SQL, кроме самого запроса. Я не очень знаком с SQL, и я действительно не понимаю основы того, как работают миграции. Можно ли построить базу данных, а затем перенести ее в новую версию, не устанавливая сначала приложение, а затем мигрируя базу данных в обновленной версии? Если это не так и если для создания виртуальной таблицы fts требуется миграция, как вы можете отправить новое приложение для Android с готовым к использованию fts ?! Я чувствую, что в моих знаниях есть зияющие дыры, которые мешают мне прогрессировать. Будем весьма благодарны за любые хорошие предложения или предложенные решения!