如何使用Android Room搜索一个或多个单词的任意组合,而不管其顺序如何

问题描述

以我的Dao中的以下查询为例,我已经能够在Android Room + FTS中实现基本的搜索功能

@Query("SELECT * FROM Conversation JOIN ConversationFts ON Conversation.id == ConversationFts.id WHERE ConversationFts.title LIKE :text GROUP BY Conversation.id")
public abstract DataSource.Factory<Integer,Conversation> search(String text);

text在百分号之间传递,例如%lorem%

此示例非常适合单个单词的搜索,我想扩展它以能够搜索一个或多个单词,但条件是它们不必按输入顺序排列,但必须匹配所有单词。这意味着这必须是AND而不是OR的情况。

我找到了一些SQL查询的示例,但是它们需要针对每种情况量身定制的特定查询,例如:LIKE文本AND LIKE另一个AND LIKE, etc ...解决方案。

如何实现?为了明确起见,我不是要寻找原始查询解决方案,而是要尽可能地坚持使用Room,否则,我宁愿直接使用它而不是求助于原始查询


编辑:每个请求均添加示例

搜索do,返回的结果包括标题中包含do的所有匹配项,即使是部分匹配项

搜索dotest,返回的结果包括所有包含dotest的匹配项,但是没有特定的顺序,即使它们是部分匹配项也是如此。

但是,如果在文本中仅找到其中之一,则不会在结果中返回它。例如,如果找到do,但没有找到test,那么它将不属于结果的一部分。

解决方法

我认为除了动态创建原始查询外,没有其他方法可以做到这一点。您可以编写其他方法,如下所示:

public abstract class ConversationDao {

    public DataSource.Factory<Integer,Conversation> search(String text) {
        StringBuilder builder = new StringBuilder();
        String[] words = text.split("\\s+");

        if (words.length > 0) {
            builder.append(" WHERE ");
        }

        for (int i = 0; i < words.length; i++) {
            builder.append("ConversationFts.title LIKE %").append(words[i]).append("%");
            if (i < words.length - 1) {
                builder.append(" AND ");
            }
        }

        SupportSQLiteQuery query = new SimpleSQLiteQuery(
                "SELECT * FROM Conversation JOIN ConversationFts ON Conversation.id == ConversationFts.id"
                        + builder.toString()
                        + " GROUP BY Conversation.id"
        );
        
        return search(query);
    }

    @RawQuery
    public abstract DataSource.Factory<Integer,Conversation> search(SupportSQLiteQuery query);

}