You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Redis OM Python高效删除Feed数组元素?

问题描述

我正在使用Redis OM for Python,模型定义如下:

from typing import List

from pydantic import BaseModel
from redis_om import EmbeddedJsonModel, Field, JsonModel, Migrator


class FeedItem(EmbeddedJsonModel):
    id: str = Field(index=True)
    s_score: str = Field()
    i_score: str = Field()
    factors: List[str]


class Feed(JsonModel):
    user_id: str = Field(index=True, primary_key=True)
    feed_items: List[FeedItem] = Field(default=[])

对应的数据结构示例:

{
    "user_id": "john_001",
    "feed_items": [
        {
            "pk": "01GS2N47G8WK2831GNHMGRVDJT",
            "id": "63e8c53825e41aca93229eac",
            "s_score": "0.5082375478927202",
            "i_score": "0.04626620037029417",
            "factors": ["2nd"],
        },
        {
            "pk": "01GS2N557FTV0SCK5TP2KENVAF",
            "id": "63e8c5d31e033af45abfb64d",
            "s_score": "0.7",
            "i_score": "0.37718576424604",
            "factors": ["2nd", "computer", "laptop"],
        },
        {
            "pk": "01GS2N63S6VM1HZ6RJVH6M1XQJ",
            "id": "63e8c743414c482153e332e6",
            "s_score": "0.5082375478927202",
            "i_score": "0.24141123225673727",
            "factors": ["2nd", "thumbdrive", "portables"],
        },
    ],
}

当用户查看了pk为01GS2N47G8WK2831GNHMGRVDJT的FeedItem后,需要将其从feed_items数组中删除。目前的实现方式是查询Feed对象、读取列表、移除元素后重新保存:

feed = Feed.find(Feed.user_id == "john_001").first()
feed_items = feed.feed_items
new_feed_items = [item for item in feed_items if item.pk != "01GS2N47G8WK2831GNHMGRVDJT"]
feed.feed_items = new_feed_items
feed.save()

但该操作耗时较长,我们有数万用户的Feed数据,且每秒会执行多次此类删除操作,请问是否有更高效的实现方式?

高效实现方案

1. 直接调用Redis JSON命令操作数组(推荐)

Redis OM底层基于Redis的JSON数据类型,你可以绕过ORM封装,直接用JSON.ARRDEL命令删除数组中的指定元素,无需全量读写整个对象:

from redis_om import get_redis_connection

redis = get_redis_connection()
feed_key = f"Feed:john_001"
target_pk = "01GS2N47G8WK2831GNHMGRVDJT"

# 获取feed_items数组,定位目标元素的索引
items = redis.json().get(feed_key, "$.feed_items")
if items:
    for idx, item in enumerate(items[0]):
        if item["pk"] == target_pk:
            redis.json().arrdel(feed_key, f"$.feed_items[{idx}]")
            break

该方式仅需两次Redis操作:一次读取数组(仅加载feed_items字段),一次删除元素,相比全量读写开销大幅降低。

2. 调整数据结构,拆分FeedItem存储

若feed_items数量较大,遍历数组找索引仍有开销,可以将每个FeedItem单独存储,并用有序集合维护用户的Feed列表:

  • 每个FeedItem的键为 FeedItem:{user_id}:{pk}
  • 用户Feed列表用有序集合FeedList:{user_id}存储,成员为FeedItem的pk,分数可用于排序(如时间戳、优先级)

删除操作直接操作有序集合和独立键:

redis = get_redis_connection()
user_id = "john_001"
target_pk = "01GS2N47G8WK2831GNHMGRVDJT"

redis.zrem(f"FeedList:{user_id}", target_pk)
redis.delete(f"FeedItem:{user_id}:{target_pk}")

这种方式的删除操作是O(1)级别的,适合高频删除场景,但需要调整数据模型和读写逻辑,不再依赖嵌套的EmbeddedJsonModel。

3. 优化现有ORM操作

如果不想改动数据结构,可以通过投影查询和字段更新减少开销:

# 仅读取feed_items字段,减少数据传输
feed_data = Feed.find(Feed.user_id == "john_001").first(projection=["feed_items"])
feed_items = feed_data.feed_items
new_feed_items = [item for item in feed_items if item.pk != "01GS2N47G8WK2831GNHMGRVDJT"]

# 直接更新feed_items字段,而非保存整个对象
Feed.update(Feed.user_id == "john_001", feed_items=new_feed_items)

用projection减少读取的数据量,用update方法仅更新目标字段,避免全量序列化和写入整个对象。

内容的提问来源于stack exchange,提问作者knl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 14:50:22