双向词典应用程序的搜索查询设计
Search query design for two-way dictionary app
我目前正在使用 SQLite + Room 为 Android 开发双向字典应用程序。
双向,我的意思是用户可以使用任何一种语言进行搜索并获得相关结果。
我想实现的一个关键功能是允许用户不必切换当前用于搜索的语言。例如。他们不必按按钮即可使用 X 语言或 Y 语言进行搜索。
不幸的是,至少据我所知,这意味着我只能使用一个查询进行搜索。
我的数据库当前设置如下(如果需要我可以更改模式):
Words 中的行数约为 129,000,Glosses 约为 150,000。
这里的gloss表示翻译,每个词都有多个gloss,pos表示词性。除 id 外,所有字段都是文本。我正在使用 Room 访问我的数据库。
目前我在我的 DAO 中有一个非常(我认为至少)天真的 SQL 可以得到我想要的东西:
@Transaction
@Query("SELECT * FROM words WHERE word LIKE :searchQuery || '%' " +
"UNION " +
"SELECT words.* FROM words INNER JOIN glosses ON words.id = glosses.word_id WHERE glosses.gloss LIKE :searchQuery || '%' ")
DataSource.Factory<Integer, WordWithGlosses > getWordWithGlosses(String searchQuery);
问题是这太慢了,大多数查询至少需要 2-3 秒,这是不可接受的table(很确定这是因为 UNION 但不确定如何在没有它)。
更详细地说,目标是从单词 table 中获取一行,该行的注释与 searchQuery 匹配。然后 Room 使用模板创建一个 WordWithGlosses 对象:
public class WordWithGlosses {
@Embedded
public Word word;
@Relation(
parentColumn = "id",
entityColumn = "word_id"
)
public List<Gloss> glosses;
public WordWithGlosses(Word word, List<Gloss> glosses) {
this.word = word;
this.glosses = glosses;
}
public Word getWord() {
return word;
}
public List<Gloss> getGlosses() {
return glosses;
}
public String getGlossesPreview() {
StringBuilder sb = new StringBuilder();
for (Gloss gloss : glosses) {
sb.append(gloss.getGloss());
sb.append("\n");
}
return sb.toString();
}
}
然后我使用这个对象来填充我的 RecyclerView(每个条目对应于这些对象之一)。此外,如果用户搜索单词 X,则相关条目会出现在我的 RecyclerView 中。此外,如果他们搜索单词 X 的众多注解之一,则会出现相同的条目。
两个问题:
- 我是否应该为永远不会更改数据库的应用程序使用 Room?我怀疑 Room 使用的对象映射方法可能会减慢速度。我主要使用它是因为大多数 Android 教程都使用它,但我现在质疑这个决定。不过比起SQLiteHelper + cursors.
用起来还是很方便的
- 有没有明显的方法可以提高这个查询的速度。我知道索引(我目前在words.word两列注释上都有一个索引。我也知道FTS4但是在运行一些测试查询之后如果我仍然保持它不会显着提高性能相同的 UNION 方法。
谢谢。
您可以在不使用 UNION
的情况下编写查询,如下所示:
SELECT w.*
FROM words w LEFT JOIN glosses g
ON w.id = g.word_id
WHERE w.word LIKE :searchQuery || '%' OR g.gloss LIKE :searchQuery || '%'
我假设 words.id
是 words
的主键,因此您可能需要 glosses.word_id
的索引。
您也可以阅读 The LIKE Optimization 来测试并尝试优化 WHERE
子句中的条件。
我从来没有使用过 ROOM,所以我不知道它的优缺点,但是如果像你说的那样应用程序永远不会更改数据库那么我找不到在您的应用程序和数据库之间添加一个额外层的原因。
尝试 SQLiteOpenHelper class.
我目前正在使用 SQLite + Room 为 Android 开发双向字典应用程序。 双向,我的意思是用户可以使用任何一种语言进行搜索并获得相关结果。
我想实现的一个关键功能是允许用户不必切换当前用于搜索的语言。例如。他们不必按按钮即可使用 X 语言或 Y 语言进行搜索。
不幸的是,至少据我所知,这意味着我只能使用一个查询进行搜索。
我的数据库当前设置如下(如果需要我可以更改模式):
Words 中的行数约为 129,000,Glosses 约为 150,000。
这里的gloss表示翻译,每个词都有多个gloss,pos表示词性。除 id 外,所有字段都是文本。我正在使用 Room 访问我的数据库。
目前我在我的 DAO 中有一个非常(我认为至少)天真的 SQL 可以得到我想要的东西:
@Transaction
@Query("SELECT * FROM words WHERE word LIKE :searchQuery || '%' " +
"UNION " +
"SELECT words.* FROM words INNER JOIN glosses ON words.id = glosses.word_id WHERE glosses.gloss LIKE :searchQuery || '%' ")
DataSource.Factory<Integer, WordWithGlosses > getWordWithGlosses(String searchQuery);
问题是这太慢了,大多数查询至少需要 2-3 秒,这是不可接受的table(很确定这是因为 UNION 但不确定如何在没有它)。
更详细地说,目标是从单词 table 中获取一行,该行的注释与 searchQuery 匹配。然后 Room 使用模板创建一个 WordWithGlosses 对象:
public class WordWithGlosses {
@Embedded
public Word word;
@Relation(
parentColumn = "id",
entityColumn = "word_id"
)
public List<Gloss> glosses;
public WordWithGlosses(Word word, List<Gloss> glosses) {
this.word = word;
this.glosses = glosses;
}
public Word getWord() {
return word;
}
public List<Gloss> getGlosses() {
return glosses;
}
public String getGlossesPreview() {
StringBuilder sb = new StringBuilder();
for (Gloss gloss : glosses) {
sb.append(gloss.getGloss());
sb.append("\n");
}
return sb.toString();
}
}
然后我使用这个对象来填充我的 RecyclerView(每个条目对应于这些对象之一)。此外,如果用户搜索单词 X,则相关条目会出现在我的 RecyclerView 中。此外,如果他们搜索单词 X 的众多注解之一,则会出现相同的条目。
两个问题:
- 我是否应该为永远不会更改数据库的应用程序使用 Room?我怀疑 Room 使用的对象映射方法可能会减慢速度。我主要使用它是因为大多数 Android 教程都使用它,但我现在质疑这个决定。不过比起SQLiteHelper + cursors. 用起来还是很方便的
- 有没有明显的方法可以提高这个查询的速度。我知道索引(我目前在words.word两列注释上都有一个索引。我也知道FTS4但是在运行一些测试查询之后如果我仍然保持它不会显着提高性能相同的 UNION 方法。
谢谢。
您可以在不使用 UNION
的情况下编写查询,如下所示:
SELECT w.*
FROM words w LEFT JOIN glosses g
ON w.id = g.word_id
WHERE w.word LIKE :searchQuery || '%' OR g.gloss LIKE :searchQuery || '%'
我假设 words.id
是 words
的主键,因此您可能需要 glosses.word_id
的索引。
您也可以阅读 The LIKE Optimization 来测试并尝试优化 WHERE
子句中的条件。
我从来没有使用过 ROOM,所以我不知道它的优缺点,但是如果像你说的那样应用程序永远不会更改数据库那么我找不到在您的应用程序和数据库之间添加一个额外层的原因。
尝试 SQLiteOpenHelper class.