使用 Redis 构建轻量的向量数据库应用:图片搜索引擎(二)

本篇文章我们来继续聊聊轻量的向量数据库方案:Redis,如何完成整个图片搜索引擎功能。

写在前面

在上一篇文章《使用 Redis 构建轻量的向量数据库应用:图片搜索引擎(一)》中,我们聊过了构建图片搜索引擎的两个主要流程中的第一部分,关于如何将图片等数据集制作成向量并构建可查询的向量索引,以及如何实现以图搜图。

这篇文章中,我们来聊聊第二部分,如何快速构建一个搜索引擎交互界面,以及快速实现文本搜索图片的功能。

前置准备

本文中使用的相关程序,和之前的内容一样,都已经开源在了 soulteary/simple-image-search-engine,欢迎一键三连,😄

在继续实现搜索交互功能和文本搜索图片功能前,我们先来了解下 Clip 能够如何使用。

OpenAI Clip 模型在文本场景的两种使用方式

在上一篇文章中,我们使用 Clip 模型实现了效果还不错的以图搜图功能。如果你有留意我在文章中提到的OpenAI 公开的研究页面,你会发现 Clip 最强的能力在于文本和图片在模型中是可以通过 embeddings 被关联起来的。

Clip 实现的图文配对、标签分类检测、内容推断

以这个能力为基础前提,我们来分别聊聊 Clip 模型的两种与文本进行交互的玩法。

借助“分类检测”能力实现的文本交互

我们可以参考上一篇文章中“将图片进行向量化处理”章节的代码,并做一些简单的调整,实现下面的程序:

import torch
from transformers import CLIPProcessor, CLIPModel
from PIL import Image
import time

# 默认从 HuggingFace 加载模型,也可以从本地加载,需要提前下载完毕
model_name_or_local_path = "openai/clip-vit-base-patch16"
# 加载模型
model = CLIPModel.from_pretrained(model_name_or_local_path)
processor = CLIPProcessor.from_pretrained(model_name_or_local_path)

# 记录处理开始时间
start = time.time()
# 读取待处理图片
image = Image.open("ball-8576.png")
# 处理图片数量,这里每次只处理一张图片
batch_size = 1

# 要检测是否在图片中出现的内容
text = ['dog', 'cat', 'night', 'astronaut']

with torch.no_grad():
    # 将图片使用模型加载,转换为 PyTorch 的 Tensor 数据类型
    # 相比较第一篇文章中的例子 1.how-to-embededing/app.py,这里多了一个 text 参数
    inputs = processor(text=text, images=image, return_tensors="pt", padding=True)
    # 将 inputs 中的内容解包,传递给模型,调用模型处理图片和文本
    outputs = model(**inputs)
    # 将原始模型输出转换为类别概率分布(在类别维度上执行 softmax 激活函数)
    probs = outputs.logits_per_image.softmax(dim=1)
    end = time.time()
    # 记录处理结束时间
    print('%s Seconds'%(end-start))
    # 打印所有的概率分布
    for i in range(len(text)):
        print(text[i],":",probs[0][i])

在上面的程序中,我们依旧会对之前的示例图片进行向量化处理。但是不同的是,我们不再对图片进行向量数据转换。而是在处理图片的时候,传入一个关键词列表:['dog', 'cat', 'night', 'astronaut']。这是假如我们在搜索的时候,搜索了一些关键词,比如 dogcatnightastronaut (狗子、猫子、夜晚、宇航员)。

当模型将文本关键词列表和图片一起进行处理的时候,我们将得到一些有趣的数据,经过一些简单的计算转换后,我们就能够得到我们传入的关键词和这个图片的关联性的概率了。

将上面的程序保存为 app.py(代码保存在 soulteary/simple-image-search-engine/steps/8.use-clip-detect-element),然后使用 python app.py 执行后,我们将得到类似下面的日志结果:

0.13835740089416504 Seconds

dog : tensor(0.0005)
cat : tensor(0.0001)
night : tensor(0.0017)
astronaut : tensor(0.9976)

其中 tensor 后面的数字就是和我们的传入的关键词的相关性概率,可以看到包含“宇航员”的可能性在 99.76%,其他的几乎都在 0.05% ~ 0.1%左右的极低概率,所以这张图的答案和我们的搜索词 “宇航员(astronaut)”非常相关,适合被作为召回结果。

虽然,我们可以通过这个方式将我们搜索的内容(关键词,或抽取为关键词的搜索内容),在数据库存储的每一张图片的向量中进行循环比对,然后再选择相似度最高的结果,但是,这样效率太低了,并不推荐

使用分类方式,在搜索引擎的场景下,最合适的可能是做内容发布、上架前的“内容的安全风控”。比如我们检测到有一些内容新添加到数据库中,可以用 Clip 结合我们的要进行检测的关键词库,来判断内容是否是合法规、健康的内容,是适合展示给用户的。

或者,从工程角度考虑,我们可以预先根据自己的业务或者图片大类,来进行一些数据的存储分堆,来提升搜索响应时的性能。

借助“内容预测”能力实现的文本交互

聊完 Clip 模型的第一种文本相关应用之后,我们来看看更有效率的方案,借助其内容预测和匹配能力来完成海量图片的文本搜索。

参考上篇文章中的“实现以图搜图功能”,我们稍加修改,可以得到下面的程序:

import torch
import numpy as np
from transformers import CLIPProcessor, CLIPModel, CLIPTokenizer
import time
import redis
from redis.commands.search.query import Query

model_name_or_local_path = "openai/clip-vit-base-patch16"
model = CLIPModel.from_pretrained(model_name_or_local_path)
processor = CLIPProcessor.from_pretrained(model_name_or_local_path)
# 处理文本需要引入
tokenizer = CLIPTokenizer.from_pretrained(model_name_or_local_path)

vector_indexes_name = "idx:ball_indexes"

client = redis.Redis(host="redis-server", port=6379, decode_responses=True)
res = client.ping()
print("redis connected:", res)

start = time.time()

# 调用模型获取文本的 embeddings
def get_text_embedding(text): 
    inputs = tokenizer(text, return_tensors = "pt")
    text_embeddings = model.get_text_features(**inputs)
    embedding_as_np = text_embeddings.cpu().detach().numpy()
    embeddings = embedding_as_np.astype(np.float32).tobytes()
    return embeddings

with torch.no_grad():
    # 获取文本的 embeddings
    text_embeddings = get_text_embedding('astronaut')

query_vector = text_embeddings
query = (
    Query("(*)=>[KNN 30 @vector $query_vector AS vector_score]")
    .sort_by("vector_score")
    .return_fields("$")
    .dialect(2)
)

def dump_query(query, query_vector, extra_params={}):
    result_docs = (
        client.ft(vector_indexes_name)
        .search(
            query,
            {
                "query_vector": query_vector
            }
            | extra_params,
        )
        .docs
    )
    print(result_docs)
    for doc in result_docs:
        print(doc['id'])

dump_query(query, query_vector, {})

end = time.time()
print('%s Seconds'%(end-start))

在上面的代码中,我们引入了 CLIPTokenizer 来调用模型将文本内容(搜索内容)转换为向量数据,与我们在数据库中存储好的图片内容进行关联匹配。

与将图片处理为向量类似的是,下面的函数我们会将我们传入的文本内容“astronaut” 转换为 Redis 搜索可以使用的数据类型(昨天文章有提,不再展开):

# 调用模型获取文本的 embeddings
def get_text_embedding(text): 
    inputs = tokenizer(text, return_tensors = "pt")
    text_embeddings = model.get_text_features(**inputs)
    embedding_as_np = text_embeddings.cpu().detach().numpy()
    embeddings = embedding_as_np.astype(np.float32).tobytes()
    return embeddings

with torch.no_grad():
    # 获取文本的 embeddings
    text_embeddings = get_text_embedding('astronaut')

当我们将上面所有的代码保存为 app.py,然后使用 python app.py 执行的时候,将会得到下面的结果:

[Document {'id': 'ball-6635.png', 'payload': None, 'json': '[-0.0013241395354270935,-0.8603543639183044,-0.0833742767572403,0.11372464150190352,-0.7410403490066528,-0.11845697462558746,-0.0472899004817009,..., 0.4744824767112732,0.26192834973335266]'}]

ball-6635.png
ball-8317.png
ball-8367.png
ball-3340.png
ball-7194.png
ball-8352.png
ball-3571.png
ball-8103.png
ball-8279.png
ball-8648.png

0.012780189514160156 Seconds

我们在日志输出的结果中,得到了一串图片名称,这说明我们的“文本搜索图片”功能正确的工作啦。

如果我们将搜索结果中的图片挑选出来仔细观察的话。你会发现,功能好像效果还凑合,是吧?

使用文本关键词搜索出来的图片

上面的程序执行日志结果记录着,这次从一万张图片中进行遍历式的相似性检索,找出最像“宇航员”的图片,其实只花了 0.01 秒左右,整体性能还是非常不错的。

搜索能力检测

为了更加客观的验证检索能力,我们当然不能只做一次搜索就结束啦。接下来我们就再简单的验证下两种搜索功能。

验证文本搜索能力

刚刚搜索的是“人”,接下来我们来试试搜索物品,比如剧中多次出现的帅气十足的 “飞机”。

我们调整代码中使用的搜索关键词:“get_text_embedding('airplane’)”,执行程序后,将得到下面的结果:

ball-1227.png
ball-1228.png
ball-1853.png
ball-1574.png
ball-894.png
ball-1521.png
ball-1673.png
ball-2020.png
ball-1299.png
ball-1814.png

观察程序执行结果,可以看到多数结果都是准确的。只有个别图片找到的是在“宇宙飞船”的驾驶舱内的画面,或许飞船也是飞机的一种?

文本搜索“飞机”的结果

我们再来试试更复杂的词语,比如:“男人格斗”(get_text_embedding('men fighting'))。程序执行完毕后,找到的搜索结果是:

ball-9275.png
ball-668.png
ball-635.png
ball-2129.png
ball-931.png
ball-1537.png
ball-3719.png
ball-2039.png
ball-1487.png
ball-6731.png

可以看到,结果里多数的图片,找的还是比较准确的。

文本搜索“男人格斗”的结果

让我们继续增加难度,搜索一个更具体的场景:“城市里,男人和女人在聊天”(In the city, men and women are chatting):

ball-2483.png
ball-2485.png
ball-2508.png
ball-4198.png
ball-2509.png
ball-4189.png
ball-2488.png
ball-2507.png
ball-3640.png
ball-7721.png

虽然词汇更多,而且包含了完全不同的内容(两种性别的人,和具体的场景),程序依旧不负所望的找到了电影里,两个满足“男人和女人在城市聊天”的画面。并且结果里,多数内容依旧是对的:

文本搜索“场景化内容”的结果

验证图片搜索能力

在上一篇文章里,我们搜索过了电影中出现过的画面,效果非常不错。

所以在这篇文章里,我们就不测试简单的场景了,直接上难度:假设我们想找到电影里“玫瑰花相关”的画面,除了使用文本搜索之外,我们还可以使用网上找到的“神似的素材”来进行搜索。

网络上找到的“玫瑰花束”素材图片

使用上一篇文章中的程序进行搜索,结果如下:

ball-5868.png
ball-6347.png
ball-7227.png
ball-1000.png
ball-5872.png
ball-1001.png
ball-5869.png
ball-999.png
ball-047.png
ball-8656.png

或许是因为我们使用的图片的风格和查找图片的风格差异较大,虽然还是能够找到符合条件的内容,但是确实出现了很多毫无关联的东西:

使用外部的图片进行图搜的结果

如果你想改进搜索结果,在重新训练模型、或者参考下文进行搜索效果优化之前,不妨试试用这里面比较符合我们需求的图片,再次进行搜索。或者在网上寻找更贴近原作画面中元素的搜索素材,让内容关联度增加,增加我们搜索的到想要的内容的概率。

额外的性能优化

尽管我们在一万张图片中,搜索出最接近“宇航员”内容的图片,只花了 0.01 秒左右。

但是,如果图片数据量增加,以及用户并发量提升,哪怕我们做了充分的应用缓存,服务的性能或许还是不如我们的预期。那么,有没有什么更好的方案呢?

接下来,我们来聊聊如何针对这个图片搜索引擎做性能优化,让它更快、以及效果更好。

优化向量数据库的索引

除了提升参与计算机器的数量和性能之外,对向量数据库进行索引优化,能够带来非常明显的性能提升。

在《向量数据库入坑指南:聊聊来自元宇宙大厂 Meta 的相似度检索技术 Faiss》一文中,我提到过 “为向量索引进行分区优化” 和 “尝试使用基于量化的索引类型” 两种优化方案。

如果你想只使用向量检索,并且尽可能准确的搜索到所有的最接近的图片内容,那么直接进行分区优化就是最好的方案,在不影响搜索精度的前提下,我们能够获得非常大的性能提升。

使用沃罗诺伊图单元拆分数据后的示意图

而如果,数据量极大,我们希望尽可能节约向量数据库使用的内存或磁盘空间,则可以采用量化分区的方案。

把向量“乘积量化”主要分三步

索引只有适不适合你的场景的方案,没有最好最差一说。

对图片进行预先分类,减少每个数据库中的图片总量

即使我们可以通过上面的操作来实现非常大规模的数据的索引和查询,但是代价是我们需要的硬件规格会变高、成本也会增加。

在聊 Clip 的第一种使用方式时,我们发现可以通过传入文本,来对图像进行分类,进行类似“分库分表”的操作,让每个分类中的数据都变的精准,数据量更低一些,查询遍历性能更低。

如果我们选择对一个非常大的数据集,进行一些预分类的 ETL 整理操作,让每个数据库中将存储的数据都在合理的数量级内,那么单一数据库中的查询计算压力将会降低非常多,也就能够同时在不同的数据库中进行并行查询,带来非常明显的搜索性能提升。

扩展图片信息,增加搜索维度

当然,除了上面的这些“空间换时间”的把戏之外,我们还可以提升可搜索的维度,让搜索结果的数据来源和维度更丰富。

比如,我们可以同时将文件名、文件类型、创建时间、甚至是文件所在的网页或者视频文件的描述都存到数据库中进行“组合式查询”。

除此之外,Clip 主打理解和匹配图片与文本,还有一类模型,则主打理解图片的内容,并转换为文本。我们可以通过类似 Blip 模型,来将图片进行预先的处理,对每一张图片进行“图片内容描述生成”。

那么,在搜索的时候,就不单单能够通过“关键词”的向量和“图片”向量的相似度来返回结果了,还可以直接使用“关键词”的文本向量和“图片描述”的文本向量进行相似匹配。

细粒度提取图片内容并解析

在图片被模型描述和解析的时候,因为很多原因,模型会“抓大放小”,只输出和保留主要部分,而可能忽略掉画面中的一些微小的元素。

如果我们预先对图像进行目标检测和切分,再对内容进行向量化处理,那么在搜索的时候,除了能够和原始内容对比之外,我们还能够和这些从图像中抽取出来的内容进行查找对比。而这些被检测出的物品,在此之前可能根本不会被模型注意到。

强化文本搜索能力

之前的文章里,我们吐槽过,目前的搜索很多都是纯纯的关键词匹配。

举个例子,比如我之前在另外一篇文章提到过(“借助平面索引,完成基础的相似内容查询功能”),我想在哈利波特中搜索“哈利波特猛然睡醒”的片段内容,这个内容绝对是不曾在书里体现,依赖传统的关键词匹配是碰不到内容的,但是确实有相关片段。如果使用语义查询,我们能够很明确的搜索到“哈利做噩梦惊醒”的相关描写。

如果你想了解这块相关的内容,还可以阅读这篇文章《向量数据库入坑:传统文本检索方式的降维打击,使用 Faiss 实现向量语义检索》,在此就不赘述啦。

最后

好啦,目前老牌数据库产品中,最轻量的向量数据库 Redis 就先聊到这里啦。

或许晚些时候,我会再展开聊聊这篇文章尚未完全展开的部分。

—EOF


我们有一个小小的折腾群,里面聚集了一些喜欢折腾、彼此坦诚相待的小伙伴。

我们在里面会一起聊聊软硬件、HomeLab、编程上、生活里以及职场中的一些问题,偶尔也在群里不定期的分享一些技术资料。

关于交友的标准,请参考下面的文章:

致新朋友:为生活投票,不断寻找更好的朋友

当然,通过下面这篇文章添加好友时,请备注实名和公司或学校、注明来源和目的,珍惜彼此的时间 😄

关于折腾群入群的那些事


本文使用「署名 4.0 国际 (CC BY 4.0)」许可协议,欢迎转载、或重新修改使用,但需要注明来源。 署名 4.0 国际 (CC BY 4.0)

本文作者: 苏洋

创建时间: 2023年11月16日
统计字数: 10022字
阅读时间: 21分钟阅读
本文链接: https://soulteary.com/2023/11/16/use-redis-to-build-a-lightweight-vector-database-application-image-search-engine-part-2.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/151740.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深度学习入门(第二天)——走进深度学习的世界 神经网络模型

反向传播计算方法 简单的例子: 如何让 f 值更小,就是改变x、y、z,而损失函数也是这样,那么我们分别求偏导,则能得出每个值对结果的影响 链式法则 梯度是一步一步传的 复杂的例子: 神经网络整体架构 类生…

浪涌防护器件要选对,布局布线更重要!|深圳比创达电子EMC(上)

浪涌测试,作为最常见的EMC抗干扰测试项目之一,基本上是家用消费电子必测的项目;其测试目的是为了验证产品在承受外部的浪涌冲击时能否正常工作。 一、浪涌冲击产生机理及其防护设计 浪涌冲击主要包括雷击浪涌冲击、电力系统内部的开关噪声冲…

假如我是AI Agent专家,你会问什么来测试我的水平

1. 假如我是AI Agent专家,你会问什么来测试我的水平 作为AI Agent专家,您可能需要回答一系列关于AI代理的设计、实现和优化方面的问题。以下是一些可能的问题: AI代理的基本原理:AI代理的基本工作原理是什么?它们如何…

requests库进行HTTP请求时,有时需要传递cookies参数

在使用requests库进行HTTP请求时,有时需要传递cookies参数。但是,requests库的cookies参数只能接受CookieJar对象,而不能接受字典等其他类型的cookies。 在requests库中增加对字典类型的cookies支持,使其能够接受字典类型的cooki…

linux高级篇基础理论二(详细文档、LAMP、SHELL、sed正则表达式)

♥️作者:小刘在C站 ♥️个人主页: 小刘主页 ♥️不能因为人生的道路坎坷,就使自己的身躯变得弯曲;不能因为生活的历程漫长,就使求索的 脚步迟缓。 ♥️学习两年总结出的运维经验,以及思科模拟器全套网络实验教程。专栏:云计算技…

Coder OSS Enterprise 2.3.3 Crack

Coder OSS Enterprise是一个开源开发平台,旨在简化开发人员的编码流程。该平台专为企业级组织设计,具有针对大规模软件开发运营量身定制的功能。 首先,该软件提供了一个云环境,允许开发人员在任何地方使用任何设备处理他们的代码。…

Vue中el与data的两种写法

想必大家对Vue中的el与data并不陌生&#xff0c;接下来&#xff0c;让我为大家介绍一下el与data的两种写法吧&#xff01; 一、el的两种写法 1.new Vue时候配置e1属性。 2.先创建Vue实例&#xff0c;随后再通过vm.$mount(#root)指定el的值 <!DOCTYPE html> <html l…

结构工程师软件 Naviate Core MEP for Revit 3.4 Crk

Naviate Fabrication - 先进的建模和制造命令&#xff0c;可提高 VDC 设计师、细节设计师和承包商的生产力和收入。 Naviate MEP - 通过 MEP 工程师和设计师的建模和参数提高效率 导航架构 Naviate Architecture 完全集成到 Revit 平台中&#xff0c;增强了 BIM 提供的协作可能…

工业除尘器笔记

工业除尘器用于对工业生产产生的有害气体和粉尘进行吸附。相关标准的制定最早可以追溯到1960年代以前。注意&#xff0c;本文的附录包含一起完整的工业除尘器事故的分析和定责过程。相关事故分析定责文档源头摘自上海市政府网站。 在产品设计行业和关联下游行业&#xff0c;在…

java--俄罗斯方块

一、先看一下游戏运行时的画面 二、代码部分 1. Cell.java Cell.java&#xff1a; package demo1;import java.awt.image.BufferedImage; import java.util.Objects;/* 编写小方块类属性&#xff1a;行、列、每个小方格的图片方法&#xff1a;左移一格、右移一格、下落一格 …

【 云原生 | K8S 】kubeadm 部署Kubernetes集群

目录 1 环境准备 2 所有节点安装docker 3 所有节点安装kubeadm&#xff0c;kubelet和kubectl 4 部署K8S集群 4.1 查看初始化需要的镜像 4.2 初始化kubeadm 4.3 设定kubectl 4.4 所有节点部署网络插件flannel master&#xff08;2C/4G&#xff0c;cpu核心数要求大于2&am…

第一讲之递归与递推下篇

第一讲之递归与递推下篇 带分数费解的开关飞行员兄弟翻硬币 带分数 用暴力将所有全排列的情况都算出来 > 有三个数&#xff0c;a,b,c 每种排列情况&#xff0c;可以用两层for循环&#xff0c;暴力分为三个部分&#xff0c;每个部分一个数 当然注意这里&#xff0c;第一层fo…

Linux常用命令——bzdiff命令

在线Linux命令查询工具 bzdiff 直接比较两个.bz2压缩包中文件的不同 补充说明 bzdiff命令用于直接比较两个“.bz2”压缩包中文件的不同&#xff0c;省去了解压缩后再调用diff命令的过程。 语法 bzdiff(参数)参数 文件1&#xff1a;指定要比较的第一个.bz2压缩包&#xf…

《洛谷深入浅出基础篇》P1536 村村通——并查集

上链接&#xff1a;P1536 村村通 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P1536 上题干&#xff1a; 题目描述 某市调查城镇交通状况&#xff0c;得到现有城镇道路统计表。表中列出了每条道路直接连通的城镇。市政府 "村村通工程…

全民运动时代,气膜建筑备受瞩目

气膜体育场馆&#xff0c;作为当今新型的临时建筑运动场馆&#xff0c;在满足大型体育赛事需求方面展现出显著的优势。相较于传统体育场馆&#xff0c;气膜建筑不仅拥有更宽敞的空间&#xff0c;而且造价成本更为经济&#xff0c;成为体育场馆领域备受关注的建筑形式。 气膜建筑…

郑州市管城区工信局局长任华民一行莅临中创算力调研指导工作

2023年11月15日&#xff0c;为深入了解企业生产经营情况&#xff0c;解决发展诉求。郑州市管城区工信局局长任华民等领导一行莅临中创算力&#xff0c;中创副总经理杨光、技术总监刘朝阳、行政主管生田等人员陪同调研。 调研期间&#xff0c;双方就生产经营、“算力数据中心”…

基于SSM的校园二手物品交易市场设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

界面组件DevExpress Reporting v23.1亮点 - 全新升级报表查看器

DevExpress Reporting是.NET Framework下功能完善的报表平台&#xff0c;它附带了易于使用的Visual Studio报表设计器和丰富的报表控件集&#xff0c;包括数据透视表、图表&#xff0c;因此您可以构建无与伦比、信息清晰的报表 界面组件DevExpress Reporting v23.1已经发布一段…

如何快速找到华为手机中下载的文档

手机的目录设置比较繁杂&#xff0c;尤其是查找刚刚下载的文件&#xff0c;有时候需要捣鼓半天&#xff0c;如何快速找到这些文件呢&#xff1f;以下提供了几种方法&#xff1a; 方法一&#xff1a; 文件管理-》搜索文档 方法二&#xff1a; 文件管理-》最近 方法三&#xf…

BMS系统项目

1、通过电压监测是否冲满&#xff0c;通过电压可以监测是否放完电 电池得参数 单体过压&#xff08;充满电&#xff09; 过压恢复&#xff08;百分之90多&#xff09; 欠压保护&#xff08;百分之几得电&#xff0c;快关机了&#xff09; 欠压恢复&#xff08;就是欠压之上…
最新文章