Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/228.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 用房间实现搜索_Android_Full Text Search_Android Sqlite_Android Room_Android Search - Fatal编程技术网

Android 用房间实现搜索

Android 用房间实现搜索,android,full-text-search,android-sqlite,android-room,android-search,Android,Full Text Search,Android Sqlite,Android Room,Android Search,最近我一直在胡闹(更具体地说),但我遇到了一些障碍 我已经成功地建立了一个房间数据库,其中存储了部门及其人员的列表。以前,这些数据是从服务器中提取的,但没有存储在本地。搜索功能也是远程处理的,所以现在我也希望在本地处理搜索功能,但我对SQL的知识有点缺乏 查看服务器上的SQL代码,search语句使用一组REGEXP函数根据提供的查询搜索两个数据库。这似乎不是处理搜索的最佳方式,但它工作得相当好,并给出了快速响应。因此,我尝试在本地模拟这一点,但很快发现,REGEXP在Android上不受支持(

最近我一直在胡闹(更具体地说),但我遇到了一些障碍

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

查看服务器上的SQL代码,search语句使用一组
REGEXP
函数根据提供的查询搜索两个数据库。这似乎不是处理搜索的最佳方式,但它工作得相当好,并给出了快速响应。因此,我尝试在本地模拟这一点,但很快发现,
REGEXP
在Android上不受支持(不使用NDK)

至于
LIKE
GLOB
操作符,它们的功能似乎非常有限。例如,我看不到一种方法可以同时匹配多个关键字;而对于
REGEXP
,我可以用
|
)操作符替换空白来实现此功能

因此,寻找我遇到的替代方案(FTS);这是在中演示的方法。尽管FTS似乎是用来搜索完整文档的,而不是像我的用例那样简单的数据

无论如何,金融时报

所以,很自然地,我试图通过创建一个实现FTS虚拟表而不是标准表来强制Room创建一个FTS虚拟表。此实现几乎是默认的
FrameworkSQLiteOpenHelperFactory
和相关框架类的直接副本。必要的代码位位于
SupportSQLiteDatabase
中,我在其中重写
execSQL
,以便在必要时插入虚拟表代码

类FTSqlite数据库(
私有val委托:SQLiteDatabase,
私有值覆盖:数组
):SupportSQLiteDatabase{
//省略的代码。。。
重写sql(sql:字符串){
delegate.execSQL(injectVirtualTable(sql))
}
重写sql(sql:String,bindArgs:Array){
delegate.execSQL(injectVirtualTable(sql)、bindArgs)
}
私有虚拟化(sql:String):String{
如果(!shouldOverride(sql))返回sql
var newSql=sql
val tableIndex=sql.indexOf(“表”)
如果(tableIndex!=-1){
sql=sql.substring(0..(tableIndex-1))+“虚拟”+sql.substring(tableIndex)
val argumentIndex=sql.indexOf(“(”)
if(argumentIndex!=-1){
sql=sql.substring(0..(argumentIndex-1)+“使用fts4”+sql.substring(argumentIndex)
}
}
返回新闻SQL
}
private-fun-shouldOverride(sql:String):布尔值{
如果(!sql.startsWith(“创建表”))返回false
val split=sql.split(“`”)
如果(split.size>=2){
val tableName=split[1]
return.contains(tableName)
}否则{
返回错误
}
}
}
这有点乱,但它可以工作!好吧,它创建了虚拟表

但是我得到了以下
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)
04-04 10:54:12.146 20289-20386/com.example.app E/SQLiteLog:(1)无法在虚拟表上创建触发器
04-04 10:54:12.148 20289-20386/com.example.app E/ROOM:无法运行失效跟踪器。数据库是否关闭?
android.database.sqlite.SQLiteException:无法在虚拟表(代码1)上创建触发器,编译时:如果不存在,则创建临时触发器`room\u table\u modification\u TRIGGER\u departments\u UPDATE`在`departments`上更新后开始插入或替换到room\u table\u modification\u日志值(null,0);结束
位于android.database.sqlite.SQLiteConnection.nativePrepareStatement(本机方法)
位于android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:890)
位于android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:501)
位于android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
位于android.database.sqlite.SQLiteProgram.(SQLiteProgram.java:58)
位于android.database.sqlite.SQLiteStatement.(SQLiteStatement.java:31)
位于android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:1752)
位于android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1682)
位于com.example.app.data.ftsqlitedatabase.execSQL(ftsqlitedatabase.kt:164)
位于android.arch.persistence.room.invalizationtracker.startTrackingTable(invalizationtracker.java:204)
在android.arch.persistence.room.invalizationtracker.access$300(invalizationtracker.java:62)
在android.arch.persistence.room.invalizationtracker$1.run(invalizationtracker.java:306)
位于java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
位于java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
运行(Thread.java:764)
Room创建了表,但随后尝试在虚拟表上创建触发器。如果我尝试覆盖触发器(即阻止它们执行),我猜这将破坏Room的许多功能。我假设,这就是Room首先不支持FTS的原因

太长,读不下去了
因此,如果Room不支持FTS(我无法强制它),并且不支持
REGEXP
(除非我使用NDK);在使用Room时,有没有其他方法可以实现搜索?FTS是正确的方法吗(似乎有些过分了),或者有其他更适合我的用例的方法吗?

我可以确认这是有效的。这会让人恼火,但确实有效

首先,您需要创建表。对于初始数据库创建,您可以使用
Ro
RoomDatabase.Builder<BookDatabase> b=
  Room.databaseBuilder(ctxt.getApplicationContext(), BookDatabase.class,
    DB_NAME);

b.addCallback(new Callback() {
  @Override
  public void onCreate(@NonNull SupportSQLiteDatabase db) {
    super.onCreate(db);

    db.execSQL("CREATE VIRTUAL TABLE booksearch USING fts4(sequence, prose)");
  }
});

BookDatabase books=b.build();
  @RawQuery
  protected abstract long insert(SupportSQLiteQuery queryish);

  void insert(ParagraphEntity entity) {
    insert(new SimpleSQLiteQuery("INSERT INTO booksearch (sequence, prose) VALUES (?, ?)",
      new Object[] {entity.sequence, entity.prose}));
  }
  @RawQuery
  protected abstract List<BookSearchResult> _search(SupportSQLiteQuery query);

  List<BookSearchResult> search(String expr) {
    return _search(query(expr));
  }

  private SimpleSQLiteQuery query(String expr) {
    return new SimpleSQLiteQuery("SELECT sequence, snippet(booksearch) AS snippet FROM booksearch WHERE prose MATCH ? ORDER BY sequence ASC",
      new Object[] {expr});
  }