- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我想通过使用redis 来提高应用程序的性能。我成功地将它用于缓存和计数器,现在正尝试使用它来搜索我 friend 的事件。
我们有 2 个表:
我需要能够让我 friend 的事件按时间戳排序。在 sql 中它可能看起来像:
SELECT act.activity, act.timestamp FROM activities act
JOIN friends fr ON fr.friend=act.user AND fr.user="{user}"
WHERE act.timestamp < {last}
ORDER BY act.timestamp DESC
LIMIT {limit}
UPD 要点:https://gist.github.com/nanvel/8725b9c71c0040b0472b
更新时间:https://gist.github.com/nanvel/8725b9c71c0040b0472b#file-timings-sqlite-vs-redis
我使用 Redis 的实现(考虑一下,用户可以有数千个 friend 和数百个事件):
import os.path
import sqlite3
import redis
import time
import uuid
class RedisSearch(object):
@property
def conn(self):
if hasattr(self, '_conn'):
return self._conn
self._conn = redis.StrictRedis(host='localhost')
return self._conn
def clean(self):
for key in self.conn.keys('test:*'):
self.conn.delete(key)
def add_friend(self, user, friend):
self.conn.sadd('test:friends:{user}'.format(user=user), friend)
def add_activity(self, user, activity, timestamp):
pipe = self.conn.pipeline()
pipe.zadd('test:last_user_activity', timestamp, user)
pipe.zadd('test:user_activities:{user}'.format(user=user), timestamp, activity)
pipe.execute()
def search(self, user, last, limit):
tmp_key = 'text:tmp:{user}'.format(user=user)
pipe = self.conn.pipeline(False)
pipe.zinterstore(
dest=tmp_key,
keys=['test:last_user_activity', 'test:friends:{user}'.format(user=user)],
aggregate='max')
pipe.zrevrange(tmp_key, 0, -1)
pipe.delete(tmp_key)
users = pipe.execute()[1]
if not users:
return []
user_keys = []
for u in users:
user_keys.append('test:user_activities:{user}'.format(user=u))
pipe = self.conn.pipeline(False)
pipe.zunionstore(dest=tmp_key, keys=user_keys, aggregate='max')
pipe.zremrangebyscore(tmp_key, min=last, max=get_timestamp())
pipe.zrevrange(tmp_key, 0, limit-1)
pipe.delete(tmp_key)
return pipe.execute()[2]
def get_timestamp():
return int(time.time() * 1000000)
if __name__ == '__main__':
db_path = os.path.join(
os.path.dirname(os.path.realpath(__file__)), 'activities.sqlite3')
con = sqlite3.connect(db_path)
redis_search = RedisSearch()
redis_search.clean()
with con:
cur = con.cursor()
cur.executescript(u"""
DROP TABLE IF EXISTS activities;
DROP TABLE IF EXISTS friends;
CREATE TABLE activities(id INTEGER PRIMARY KEY, user VARCHAR(31), activity VARCHAR(31), timestamp INTEGER);
CREATE TABLE friends(id INTEGER PRIMARY KEY, user VARCHAR(31), friend VARCHAR(31));
""")
authors = []
for i in xrange(100):
# create 100 activities
author = uuid.uuid4()
authors.append(author)
activity = uuid.uuid4()
timestamp = get_timestamp()
cur.executescript(u"""
INSERT INTO activities(user, activity, timestamp) VALUES("{user}", "{activity}", {timestamp});
""".format(user=author, activity=activity, timestamp=timestamp))
redis_search.add_activity(user=author, activity=activity, timestamp=timestamp)
user = uuid.uuid4()
for i in xrange(100):
# create friends
friend = uuid.uuid4()
cur.executescript(u"""
INSERT INTO friends(user, friend) VALUES("{user}", "{friend}");
""".format(user=user, friend=friend))
redis_search.add_friend(user=user, friend=friend)
# more friends
for i in xrange(100):
u = uuid.uuid4()
f = uuid.uuid4()
cur.executescript(u"""
INSERT INTO friends(user, friend) VALUES("{user}", "{friend}");
""".format(user=u, friend=f))
redis_search.add_friend(user=u, friend=f)
# add outhors to friends
for i in xrange(20):
cur.executescript(u"""
INSERT INTO friends(user, friend) VALUES("{user}", "{friend}");
""".format(user=user, friend=authors[i]))
redis_search.add_friend(user=user, friend=authors[i])
# select my friends activities
last = get_timestamp()
for i in xrange(2):
print '--- page {n} ---'.format(n=i + 1)
cur.execute(u"""
SELECT act.activity, act.timestamp from activities act
JOIN friends fr ON fr.friend=act.user AND fr.user="{user}"
WHERE act.timestamp < {last}
ORDER BY act.timestamp DESC
LIMIT {limit}
""".format(user=user, last=last, limit=10))
new_last = last
for r, timestamp in cur:
print r
new_last = timestamp
print '---'
for r in redis_search.search(user=user, last=last, limit=10):
print r
last = new_last
非常感谢您的回答!
更新:我用 lua 重写了搜索函数:
def search(self, user, last, limit):
SCRIPT = """
redis.call("ZINTERSTORE", "test:tmp:" .. ARGV[1], 2, "test:last_user_activity", "test:friends:" .. ARGV[1], "AGGREGATE", "MAX")
local users = redis.call("ZREVRANGE", "test:tmp:" .. ARGV[1], 0, -1, "WITHSCORES")
if users == nil then
return {}
end
redis.call("DEL", "test:tmp:" .. ARGV[1])
local counter = 0
local lastval = users[1]
for k, v in pairs(users) do
if (counter % 2 == 0) then
lastval = v
else
redis.call("ZUNIONSTORE", "test:tmp:" .. ARGV[1], 2, "test:tmp:" .. ARGV[1], "test:user_activities:" .. lastval, "AGGREGATE", "MAX")
redis.call("ZREMRANGEBYSCORE", "test:tmp:" .. ARGV[1], ARGV[2], ARGV[3])
if redis.call("ZCOUNT", "test:tmp:" .. ARGV[1], v, ARGV[2]) >= tonumber(ARGV[4]) then break end
end
counter = counter + 1
end
local users = redis.call("ZREVRANGE", "test:tmp:" .. ARGV[1], 0, ARGV[4] - 1)
redis.call("DEL", "test:tmp:" .. ARGV[1])
return users
"""
return self.conn.eval(SCRIPT, 0, user, last, get_timestamp(), limit)
更新 2016-05-19
我做错了,正确的解决方法有相关链接:
最佳答案
我不确定你的 Lua 脚本是做什么的。似乎是:
这是我的建议:
如果您的应用程序不允许用户显示任意事件页面(我的意思是如果用户只能向下滚动以查看更多内容),请考虑直接使用好友事件键并保存扫描/迭代上下文。您可以尝试以下操作:
也许您不需要 Redis 来完成这项任务。您可以使用数据库表来存储要显示给用户的列表事件。当用户添加 friend 并为每个 friend 的事件添加一个项目时,您必须预先填充它。当然,这个解决方案有利有弊,我不能最终提出建议。由您选择。
希望这对您有所帮助。
关于database-design - 使用redis获取我的 friend 事件(redis JOIN替代方案),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26820983/
我正在用power designer创建一个物理模型,我想将默认值添加到我的Mysql表中。 有可能吗,有人加了默认值 ? 谢谢 最佳答案 有可能,我发现“列属性”并不容易 方法如下: 选择表格(单击
关闭。这个问题是 opinion-based 。它目前不接受答案。 想改善这个问题吗?更新问题,以便可以通过 editing this post 用事实和引文来回答。 2年前关闭。 Improve t
我正在编写一个采用 Material Design 布局的应用程序,但找不到任何关于如何将对话框动画显示到屏幕上的指南。 这表明盒子应该只是“砰”的一声存在,但这似乎违背了设计的精神,包括动画和触觉。
我做了一个巨大的掠夺,不小心丢失了我的*.cs(设计文件)..我刚刚得到了*.designer文件。 我能否反过来,仅使用 .designer 文件以某种方式创 build 计文件 (*.cs),还是
如果 Google 的关键字规划器向我显示关键字“Web Design [city-name]”获得约 880 次搜索,而“Website Design [city-name]”获得约 620 次搜索
首先,代码: $(document).ready(function() { $('#member_pattern').hide(); $('.add-member').click(function()
大型软件公司之一问了这个问题。我想出了一个简单的解决方案,我想知道其他人对该解决方案有何看法。 You are supposed to design an API and a backend for
在最新的 Material Design 文档 (https://www.google.com/design/spec/what-is-material/elevation-shadows.html#
背景 我正在对从我们的 RDBMS 数据库到 MongoDB 的转换进行原型(prototype)设计。在进行非规范化时,似乎我有两种选择,一种会导致许多(数百万)个小文档,另一种会导致更少(数十万)
Qt Designer (5.11.2) 在选择 QWebEngineView-Widget 时崩溃。 我正在创建一个对话框,以将其作为 .ui 文件包含在 QGIS 3 中。在表单中,我想使用 QW
我直接从 getmdl.io(组件页面)和所有设备(多台 PC、浏览器、手机等)复制代码,汉堡菜单不在标题中居中。我似乎无法隔离 css 中的菜单图标来重新对齐它。 getmdl.io 上的所有组件代
如何为 SPA 动态初始化 materialize design lite (google) 的组件?当我在 View 中动态初始化组件时,JS 没有初始化。正如我已经尝试过使用 componentH
我正在使用 Angular 4 构建一个 Web 应用程序。对于设计,我使用的是 Material Design lite。但是,我想使用 MDL 实现一个交互式轮播,它给我流畅的外观和感觉,并且与我
它看起来像 Polymer Starter Kit包含比 Material Design Lite 更多的组件,并且现在可用。由于两者都是符合 Material Design 理念的 Google 项
我在设置 mdl-textfield 样式时遇到了一些困难。 具体来说,设置 float 标签的大小和颜色,以及按下输入字段后动画的高度和颜色。 实际上,这是我从组件列表中获取的起点。 https:/
所以,好友列表的现代概念: 假设我们有一个名为 Person 的表。现在,那个 Person 需要有很多伙伴(其中每个伙伴也在 person 类中)。构建关系的最明显方法是通过连接表。即 buddyI
如何在导航中创建子菜单项? Link Link Link Link 我不能用 用它。什么是正确的类? 最佳答案 MDL 似乎还没有原生支持子菜单。 然而
我想知道我应该遵循哪些步骤来解决设计自动售货机等问题并提出许多设计文档(如用例、序列图、类图)。是否有任何我可以阅读的来源/链接,其中讨论了如何逐步进行。 谢谢。 最佳答案 我不确定是否有任何普遍接受
早在 10 月份,Kristopher Johnson 就询问了 Accounting Software Design Patterns 他收到了几个答案,但基本上都是一样的,都指向Martin Fo
我一直在为我们的产品开发一些组件,其中之一是基于流布局面板。 我想做的是为它提供一个自定义设计器,但不会丢失其默认设计器 (System.Windows.Forms.Design.FlowLayout
我是一名优秀的程序员,十分优秀!