1

我有以下情况:

  • 我有一个对象Song,其属性之一是Name.
  • 我有一个 sqlite 数据库,可以包含多达百万条记录的歌曲。
  • 我需要对歌曲的名称属性进行实时搜索(用户点击字母后,应用程序将直接搜索它)。

我一直在想的解决方案(我没有做任何代码)是:

  1. 直接查询 sqlite(我认为这是最糟糕的解决方案,因为我需要从 sqlite 获取并将其放入Cursor
  2. 将所有 sqlite 记录放到 List 或 ArrayList 中,然后我不确定从哪里继续,因为我认为 for 循环不是最好的解决方案,因为我需要存储到其他 List 以预填充我的ListView

谁能给我一个想法,也许只是概念,来解决这个问题?

4

3 回答 3

2

你应该为你的查询做缓存。为此构建一个内存数据结构,具有级联结构(一次一个字母)。

限制特定查询的返回对象的数量(例如,最多返回 10 个)。显然,您不想返回所有Song以 letter 开头的 s A。此外,此列表可能基于重要性(或选择频率) - 您也可以存储它。

对于缓存的内部表示,我推荐这样的东西:

public class SongCacheNode {
    private String selector;
    private Map<Character, SongCacheNode> subCaches = 
        new HashMap<Character, SongCacheNode>();
    private List<Song> selection = new ArrayList<Song>(10);
    private boolean leafNode = false;
    private boolean containsAll = false;
}

您可以构建一个树状结构。

  • selector存储该节点的字符串选择器(例如歌曲标题的前缀)。
  • 可以为下subCaches一个字母存储下一个缓存。
  • 可以存储选择的selection歌曲标题
  • leafNode说没有更多数据存储在缓存中,您可以使用selection,或者您必须这样做SQL- 存储在containsAll
  • 如果containsAll是真的,那么所有可能的歌曲都存储在 中selection,如果不是,你仍然需要做 SQL

此结构允许您根据歌曲标题分布构建可变深度缓存。此外,对于选择,您可以选择任何匹配,不仅是前缀匹配(例如许多歌曲标题以“The”开头),进行不区分大小写的查询等。您也可以进行部分缓存,以限制内存使用(例如,最多存储 5 个字符,或者即使有大量歌曲也不存储不常见的查询) - 只需设置containsAllfalse.

于 2013-04-07T12:18:36.223 回答
0

SQL lite 允许全文搜索功能。鉴于歌曲名称也可以使用“thrill”等部分术语进行搜索| '惊悚' | '惊悚 MJ',你应该去。

虽然全文搜索会被索引,但根据负载的不同,数据库可能无法承受,在这种情况下,您可以构建歌曲名称的trie。所有匹配的歌曲都可以从最后一个匹配节点的子节点获得,这个结构将在内存中。那应该让它很快。

将歌曲详细信息加载到列表/集将无济于事,因为您无法进行部分匹配。List / Set 要么包含“thril”,要么不包含。除非您使用全文搜索或像trie这样的内存中的 DS,否则无法知道部分字符串是否与数据库中的某些内容匹配。

于 2013-04-07T12:21:03.373 回答
0

您的选择
通过将所有歌曲加载到列表中,您将加快搜索时间。但是,这将极大地影响加载时间。

如果您没有将所有歌曲都加载到程序中,那么您的加载时间会更短,但可能会更长的搜索延迟。

我会去哪一个

简单来说,我会选择后者。这里的优点是您可以在用户键入时在另一个线程中进行数据库调用。多线程你的应用程序意味着一个线程,用户可以愉快地输入,而在另一个线程上,将发生艰巨的数据库调用,并且可以加载数据。

一些需要注意的事情/您可能想要使用的想法。

如果您的数据库有一百万首歌曲,可以肯定地说会有很多歌曲以相同的字母开头。也许在最初的几次按键上不进行数据库调用会对您有利,原因有很多:

  1. 每次按键后,您都不会收到大量数据。
  2. 它将减少您的程序必须处理的数据量,从而降低性能损失。
  3. 这将为客户端提供一个不那么令人生畏的用户界面。想象一下输入一首歌曲并看到一个十万首歌曲的列表突然出现。它不具备流畅的可用性。

另一个想法是在每次查询时缓存数据。考虑到这一点,可以非常快速地获得相同的数据。

于 2013-04-07T12:21:13.127 回答