2

我发现Redis为我的项目提供了非常好的功能(webapp 的自动完成后端)。基本上,它是我的全文搜索引擎。现在我正在寻找 Redis 的替代品,因为我无法将整个数据集保存在内存中。

我像这样创建我的 Redis 商店(找不到这个想法的学分链接):

  1. 我在每个字符之后将我的(加权)项目从常规数据库分成 3 个字符块(“单词”-> ['wor', 'ord', 'rds']
  2. 每个块都成为保存具有此类块的项目 id-s 的排序列表的键。( ZADD chunk weight items_id)
  3. 每个项目 id 也是保存一些关于项目 ( SET items_id items_hash_in_json)的简单 JSON 文档的关键

搜索工作如下:

  1. 查询字符串以相同的方式分成 3 个字符块
  2. 我询问所有这些块的交集并获取 items_id-s 列表(ZINTERSTORE和的组合ZRANGEBYSCORE
  3. 通过 items_id-s 返回 JSON 文档列表

干净利落。非常有效和快速。在这样的流程中仍然存在一些较小的缺点,但大多数情况下,我觉得我的域拥有正确的工具和正确的数据类型。

主要问题是:它需要太多的内存。我在数据库中有大约 60 万个项目,在“索引”上,我在 40 个字符后将它们删除,但仍需要 2.5GB RAM。这个任务有点多。数据集会增长,不会太多也不会太快,但仍然会增长。

我现在查看了一些 NoSQL 存储,但我还没有遇到像 Redis 那样的类似方法和工具。也许是因为我现在对每项工作都很认真,但我觉得对于其他 NoSQL 存储,我需要自己实现这样的功能(排序列表,找到它们的交集,简单的键值作为二进制字符串,插入数据非常简单,简单协议/API 和简单客户端)。

我也希望有 Perl 绑定,但在非常简单的协议(如 CoachDB 的 REST)的情况下,这不是强制性的。

你知道用其他 NoSQL 产品实现我的解决方案的工具吗?

换个角度来看,我也已经在寻找完全不同的解决方案(比如couchdb-lucene,但我想避免放弃上面描述的系统。

4

2 回答 2

1

HTTP 缓存 我有一个可能的解决方案,我目前在我的网站上使用。我使用 Nginx 缓存带有静态文件的自动完成查询。Nginx 可以非常快速地提供静态文件。这是我的配置中的示例行。

http {

    fastcgi_cache_path /var/cache/nginx levels=1:2
            keys_zone=tt:600m
            inactive=7d max_size=10g;

    fastcgi_temp_path /var/cache/nginx/tmp;

}

此块描述了将存储文件的路径。级别是多少目录深,1:2就足够了。我这里的区域叫做 tt,你可以随意命名。其次是到期时间。

location ~ /tt/(.+)\.php$ {
            try_files $uri /index.php?$args;
            fastcgi_index   index.php;
            fastcgi_pass    127.0.0.1:9000;
            include         fastcgi_params;
            fastcgi_param   SCRIPT_FILENAME    $document_root$fastcgi_script_name;
            fastcgi_param   SCRIPT_NAME        $fastcgi_script_name;

                #Caching parameters
                fastcgi_cache tt;

                fastcgi_cache_key "$scheme$request_method$host$request_uri";

                fastcgi_cache_valid  200 302 304 30m;
                fastcgi_cache_valid  301 1h;
                fastcgi_cache_valid  any 5m;
                fastcgi_cache_use_stale error timeout invalid_header updating http_500;
        }

位置块将包含缓存参数。所以任何带有 URI /tt/.*.php 的东西都会被缓存。URI + 查询字符串将成为缓存键。

如果你不使用 Nginx,同样的概念可能适用于另一个网络服务器。我希望这有帮助。

编辑

来自评论: 使用索引作为普通文件似乎比 SQL 查询慢。不过,我还没有对它们进行基准测试。

Nginx 的缓存命中将如下所示:

-> Nginx -> 文件

错过:

-> Nginx -> php/python/ruby -> db(redis/mysql/whatever)

第一条路径可能看起来更慢,因为您想到了 diskio,但事实并非如此,操作系统会自动缓存经常访问的文件。因此,当 Nginx 升温时,相比之下,只需在 PHP 后端说“Hello world”就会变得更慢。我提出这样的要求是因为它就像提供静态文件一样。

实际命中/未命中率取决于应用程序、数据和配置。以我的经验,人们使用很多相同的搜索词,所以你可能不会有 600k 的文件。即使你这样做并没有真正的伤害,Nginx 会为你管理它们。如果您的数据变化很大并且您希望搜索快速反映这些变化,则此方法不是很好。您将不得不设置一个较短的过期时间,这会导致更多的未命中。

Redis Zip 列表/哈希 http://redis.io/topics/memory-optimization

如果您仍需要排序集,请确保链接中的配置设置设置得足够高以满足您的数据集需求。如果您能够使用哈希,则可以使用它们在该页面上显示较低的算法节省大量内存。我认为您绝对可以在存储链接到 json 字符串的 item_id 时使用它。

于 2013-01-31T03:43:26.430 回答
0

只是一个简单的想法,可能对你有用。这不是对您的问题的直接和准确的答案。

我想您的大部分数据或重要部分都位于那些 JSON 文档中。在这种情况下,我建议您稍微更改您的数据基础架构:为了保留 Redis 的所有优点,您应该使用相同的前 2 步进行创建搜索,但更改您的第 3 步。无需使用 Redis 来存储这些 JSON 文档,只需将它们移动到您首选/使用的数据库的简单索引表中即可。这样,您将只处理块和键并执行 Redis 提供的操作,但在第 3 步中,您将获取 item_id 的列表并从数据库中检索 JSON 数据。大概一个SELECT ... WHERE item_id IN(...)就够了。

于 2013-01-31T13:13:25.930 回答