I have been trying to use new Android's Room 2.1 feature of FTS table to enable search functionality.
Entity:
@Entity
class ChatMessageEntity(
@PrimaryKey
var messageId: String,
var messageUser: String,
var messageText: String,
)
FTS entity:
@Fts4(contentEntity = ChatMessageEntity::class)
@Entity
class ChatMessageFts(
var messageText: String //only want messageText searchable
)
Database:
@Database(entities = [ChatMessageEntity::class, ChatMessageFts::class], version = 1)
abstract class ChatMessageDatabase : RoomDatabase() {
abstract fun chatMessageDatabase(): ChatMessageDao
companion object {
fun create(context: Context) = Room.databaseBuilder(context, ChatMessageDatabase::class.java, DB_NAME).build()
}
}
DAO:
@Query("INSERT INTO ChatMessageFts(ChatMessageFts) VALUES('rebuild')") //works
suspend fun ftsRebuild()
@Query("INSERT INTO ChatMessageFts(docid, messageText) VALUES(:id, :text)") //compiles but doesn't work
suspend fun saveFtsMessage(id: Long, text: String)
I wish to add each row in FTS when I also add the row in the original table (ChatMessageEntity - not shown). When rebuilding the FTS table from scratch, it works perfectly (ftsRebuild()
above).
However, I wish to add each input individually. I have tried many things (for example saveFtsMessage()
shown above) - adding without docId, trying with rowId, ... I even tried adding a new object ChatMessageEntity
into ChatMessageFts
as input but I didn't manage to compile it due to errors.
Any suggestion on how I can add individual input in FTS table is most welcome!
@Fts4(contentEntity = ChatMessageEntity::class)
The magic of the contentEntity
property of the annotation is that Room sets up triggers to keep your FTS table in sync with the corresponding entity table:
"contentSyncTriggers": [
"CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_paragraphsFts_BEFORE_UPDATE BEFORE UPDATE ON `paragraphs` BEGIN DELETE FROM `paragraphsFts` WHERE `docid`=OLD.`rowid`; END",
"CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_paragraphsFts_BEFORE_DELETE BEFORE DELETE ON `paragraphs` BEGIN DELETE FROM `paragraphsFts` WHERE `docid`=OLD.`rowid`; END",
"CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_paragraphsFts_AFTER_UPDATE AFTER UPDATE ON `paragraphs` BEGIN INSERT INTO `paragraphsFts`(`docid`, `prose`) VALUES (NEW.`rowid`, NEW.`prose`); END",
"CREATE TRIGGER IF NOT EXISTS room_fts_content_sync_paragraphsFts_AFTER_INSERT AFTER INSERT ON `paragraphs` BEGIN INSERT INTO `paragraphsFts`(`docid`, `prose`) VALUES (NEW.`rowid`, NEW.`prose`); END"
]
(from this sample app from this book)
So long as you are inserting, updating, and deleting your entities, the FTS table will be maintained automatically. You just use the FTS table for querying purposes.
If you skip the contentEntity
annotation — and assuming that works — then you might need to maintain your FTS table independently.