实施房间搜索

布赖恩

最近,我一直在弄乱Android Architecture Components(更具体地说是Room),但遇到了一些障碍。

我已经成功建立了一个Room数据库,该数据库存储了部门及其人员的列表。以前,此数据是从服务器中提取的,但尚未存储在本地。搜索功能也是远程处理的,因此现在我也希望在本地处理搜索功能,但是我对SQL的知识有点缺乏。

查看服务器上的SQL代码,搜索语句使用一堆REGEXP函数根据提供的查询搜索两个数据库。这似乎不是处理搜索的最佳方法,但效果很好,并给出了快速响应。因此,我尝试在本地进行模拟,但是很快发现REGEXPAndroid上不支持(不使用NDK)。

对于LIKEGLOB运算符,他们似乎无能为力。例如,我看不到一种可以一次与多个关键字匹配的方法。REGEXP我可以使用or|)运算符替换空白以实现此功能。

因此,在寻找替代方案时,我遇到了全文搜索(FTS);这是Android文档中关于实现搜索演示的方法尽管看起来FTS是用于搜索完整文档的,而不是像我的用例那样简单的数据。

无论如何,Room不支持FTS

因此,自然地,我试图通过创建一个实现SupportSQLiteOpenHelper.Factory该功能的实现来强迫Room创建FTS虚拟表而不是标准表此实现几乎是defaultFrameworkSQLiteOpenHelperFactory和相关框架类的直接副本必要的代码位在中SupportSQLiteDatabase,在需要的地方我重写此位置execSQL以注入虚拟表代码。

class FTSSQLiteDatabase(
    private val delegate: SQLiteDatabase,
    private val ftsOverrides: Array<out String>
) : SupportSQLiteDatabase {

    // Omitted code...

    override fun execSQL(sql: String) {
        delegate.execSQL(injectVirtualTable(sql))
    }

    override fun execSQL(sql: String, bindArgs: Array<out Any>) {
        delegate.execSQL(injectVirtualTable(sql), bindArgs)
    }

    private fun injectVirtualTable(sql: String): String {
        if (!shouldOverride(sql)) return sql

        var newSql = sql

        val tableIndex = sql.indexOf("TABLE")
        if (tableIndex != -1) {
            sql = sql.substring(0..(tableIndex - 1)) + "VIRTUAL " + sql.substring(tableIndex)

            val argumentIndex = sql.indexOf('(')
            if (argumentIndex != -1) {
                sql = sql.substring(0..(argumentIndex - 1) + "USING fts4" + sql.substring(argumentIndex)
            }
        }

        return newSql
    }

    private fun shouldOverride(sql: String): Boolean {
        if (!sql.startsWith("CREATE TABLE")) return false

        val split = sql.split('`')
        if (split.size >= 2) {
            val tableName = split[1]
            return ftsOverrides.contains(tableName)
        } else {
            return false
        }
    }

}

有点混乱,但可以!好吧,它创建了虚拟表…

但是然后我得到以下内容SQLiteException

04-04 10:54:12.146 20289-20386/com.example.app E/SQLiteLog: (1) cannot create triggers on virtual tables
04-04 10:54:12.148 20289-20386/com.example.app E/ROOM: Cannot run invalidation tracker. Is the db closed?
    android.database.sqlite.SQLiteException: cannot create triggers on virtual tables (code 1): , while compiling: CREATE TEMP TRIGGER IF NOT EXISTS `room_table_modification_trigger_departments_UPDATE` AFTER UPDATE ON `departments` BEGIN INSERT OR REPLACE INTO room_table_modification_log VALUES(null, 0); END
        at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
        at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:890)
        at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:501)
        at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
        at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:58)
        at android.database.sqlite.SQLiteStatement.<init>(SQLiteStatement.java:31)
        at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:1752)
        at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1682)
        at com.example.app.data.FTSSQLiteDatabase.execSQL(FTSSQLiteDatabase.kt:164)
        at android.arch.persistence.room.InvalidationTracker.startTrackingTable(InvalidationTracker.java:204)
        at android.arch.persistence.room.InvalidationTracker.access$300(InvalidationTracker.java:62)
        at android.arch.persistence.room.InvalidationTracker$1.run(InvalidationTracker.java:306)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
        at java.lang.Thread.run(Thread.java:764)

Room创建了表,但是随后尝试在虚拟表上创建触发器,这显然是不允许的如果我尝试覆盖触发器(即只是阻止它们执行),我想这将破坏Room的许多功能。我认为,这是Room首先不支持FTS的原因。

TLDR

因此,如果Room不支持FTS(并且我不能强迫它)并且REGEXP不被支持(除非我使用NDK);使用Room时,我还有另一种实现搜索的方法吗?FTS甚至是正确的方法(似乎过大),还是有其他更适合我的用例的方法?

米恰拉·巴兰(MichałBaran)

我们终于得到了它,并且从2.1.0-alpha01版本开始,Room支持具有映射FTS3或FTS4表的实体。有关更多信息和示例用法,您可以转到其文档:@ Fts3@ Fts4

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章