Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/eclipse/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Database design 使用redis获取好友活动(redis加入备选方案)_Database Design_Redis_Nosql - Fatal编程技术网

Database design 使用redis获取好友活动(redis加入备选方案)

Database design 使用redis获取好友活动(redis加入备选方案),database-design,redis,nosql,Database Design,Redis,Nosql,我想通过使用redis来提高应用程序的性能。我成功地将其用于缓存和计数器,现在尝试将其用于搜索我的好友活动 我们有两张桌子: 活动(用户、活动、时间戳) 朋友(用户、朋友) 我需要能够让我的朋友活动排序的时间戳。在sql中,它可能看起来像: SELECT act.activity, act.timestamp FROM activities act JOIN friends fr ON fr.friend=act.user AND fr.user="{user}" WHERE act.tim

我想通过使用redis来提高应用程序的性能。我成功地将其用于缓存和计数器,现在尝试将其用于搜索我的好友活动

我们有两张桌子:

  • 活动(用户、活动、时间戳)
  • 朋友(用户、朋友)
我需要能够让我的朋友活动排序的时间戳。在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 2016-05-19

我做错了,有相关链接指向正确的解决方案:


我不确定您的Lua脚本的功能。似乎是:

  • 将所有活动复制到新的redis密钥,并按时间戳对其进行排序
  • 删除大多数复制的活动
  • 把剩下的拿来
  • 删除在第一步创建并包含此剩余项的密钥
  • 以下是我的建议:

    • 每次需要向用户显示最后10或20项活动时,您是否有理由创建新的完整活动列表
    • 为什么你不能保留几分钟,然后再用它来显示下一页
    • 如果要在同一个Lua脚本中删除密钥,为什么要要求Redis server从排序集中删除项

    如果您的应用程序不允许用户显示任意活动页面(我的意思是,如果用户只能向下滚动查看更多),请考虑直接使用朋友活动键,并保存扫描/迭代上下文。您可以尝试以下操作:

    • 使用ZRANGE/ZREVRANGE命令从每个朋友的活动集中获取相同数量的项目(与页面大小匹配)
    • 返回得分最高的项目(时间戳)
    • 每个活动列表最后返回的项目的位置是您的“迭代上下文”
    • 保存此上下文(例如,在用户会话中)并使用它为下一个活动页面选择数据
    也许你不需要Redis来完成这个任务。可以使用数据库表存储要显示给用户的列表活动。当用户添加朋友并为每个朋友的活动添加项目时,您必须预先填充它。当然,这个解决方案有其利弊,我不能最终提出建议。这取决于你的选择

    希望这有帮助

    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
    
    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)