pymongはmongogridfsファイルを削除します
1. 背景:
Gridfs イメージサーバーストレージ
GridFS は、MongoDB の BSON ファイル サイズ制限 (16M) を超えて保存およびクエリを実行するための仕様です。別のドキュメントにファイルを保存する BSON ファイルとは異なり、GridFS はファイルを複数のブロックに分割し、各ブロックは別のドキュメントになります。デフォルトでは、各 GridFS ブロックは 255kB です。つまり、最後のブロックを除いて (残りのファイル サイズに応じて)、ドキュメントは複数の 255kB ブロック サイズで保存されます。
GridFS は 2 つのコレクションを使用してデータを保存します。1 つのコレクションはファイル ブロック (fs.chunks) を保存し、もう 1 つはファイル メタデータ (fs.files) を保存します。fs.chunks の各チャンクのサイズは 256 KB です。Mongo のレプリカ セットと断片化アーキテクチャにより、GridFS に効率的な読み取りおよび書き込み拡張機能と高可用性機能が提供されます。画像、ビデオ、およびその他の大きなファイル用の高レベルのストレージがあります。パフォーマンス[小さいファイル、小さいファイル (< 16M) は Bson バイナリに保存され、大きいファイルは Gridfs に保存されます]。
会社のプロジェクト画像サーバーは、jpg 画像、mp3 オーディオ、ビデオ、およびサイトマップ ファイルを保存する mongo レプリカ セットの Gridfs を使用して実装されています。最近、画像サーバーには、一元的にクリーンアップする必要がある違法な画像のバッチが存在します。ファイルをバッチで。
2. 現在の問題:
Mongofsのgridfs運用計画:
mongo ファイル システム Gridfs の使用中に、mongo は管理mongofiles
用の。
[root@bj-test-wlj-2-132 twj]# mongofiles --help
Browse and modify a GridFS filesystem.
usage: mongofiles [options] command [gridfs filename]
command:
one of (list|search|put|get)
list - list all files. 'gridfs filename' is an optional prefix
which listed filenames must begin with.
search - search all files. 'gridfs filename' is a substring
which listed filenames must contain.
put - add a file with filename 'gridfs filename'
get - get a file with filename 'gridfs filename'
delete - delete all files with filename 'gridfs filename'
options:
--help produce help message
-v [ --verbose ] be more verbose (include multiple times
for more verbosity e.g. -vvvvv)
--version print the program's version and exit
-h [ --host ] arg mongo host to connect to ( <set
name>/s1,s2 for sets)
--port arg server port. Can also use --host
hostname:port
--ipv6 enable IPv6 support (disabled by
default)
-u [ --username ] arg username
-p [ --password ] arg password
--authenticationDatabase arg user source (defaults to dbname)
--authenticationMechanism arg (=MONGODB-CR)
authentication mechanism
--dbpath arg directly access mongod database files
in the given path, instead of
connecting to a mongod server - needs
to lock the data directory, so cannot
be used if a mongod is currently
accessing the same path
--directoryperdb each db is in a separate directly
(relevant only if dbpath specified)
--journal enable journaling (relevant only if
dbpath specified)
-d [ --db ] arg database to use
-c [ --collection ] arg collection to use (some commands)
-l [ --local ] arg local filename for put|get (default is
to use the same name as 'gridfs
filename')
-t [ --type ] arg MIME type for put (default is to omit)
-r [ --replace ] Remove other files with same name after
PUT
その中で、ファイルの削除操作は次のとおりです。
mongofiles ファイル名を削除 --port ポート --db ライブラリ名
mongofiles delete xxx.jpg --port 30000 --db pics
ファイルを一括削除する場合:
削除するファイルは膨大なため、一度に50~60万件になることもありますが、mongofilesコマンドでファイルを削除するたびにtcp接続を確立する必要があるので、ファイルにURLを一旦入れてから、ファイルの差分を確認し、ループ内で +sleep を実行して緩和します。TCP ポートがいっぱいです。
for file in `ls`;do for i in `cat 31aa*`;do echo " mongofiles delete $i --port 30000 --db pics" >> 2021-8-31.log && mongofiles delete $i --port 30000 --db pic sleep 0.1 ;done ; echo sleep 60 ;sleep 120 ;done
リスクポイント:
- mongofiles コマンドを使用して少量のデータを一時的に削除すると、動作が遅くなります
- tcpdumps の数と mongo 接続の数がいっぱいになるリスクがあります
- 使用中に、バッチで削除されるファイルの量が 10,000 を超えると削除が失敗することがわかりました。mongofiles は操作が成功したことを示すプロンプトを表示しますが、ファイルはまだ存在します。
3. 解決策:
開発時の一時的な解決策:
シェルコマンドによる異常ファイルの一括処理により、多数のファイルが動作しないことが判明し、一時的に開発者に処理を依頼しました。理解した後、開発では Java 言語を採用し、mongo ドライバー モジュールのカプセル化メソッド Remove を使用してファイルを直接削除します。
import com.mongodb.DB;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import com.mongodb.gridfs.GridFS;
import com.mongodb.gridfs.GridFSDBFile;
public class MyGridFsTest {
private String host = "127.0.0.1";
private int port = 27017;
private String dbName = "demogridfs";
@Test
public void testFindFile() throws IOException{
Mongo connection = new Mongo(host, port);
DB db = connection.getDB(dbName);
GridFS gridFs = new GridFS(db);
DBObject query = new BasicDBObject("filename", fileName);
gridFs.remove(query);
Java の Mongo ドライバーのセカンダリ パッケージはファイルを直接削除し、mongo スレッド プールを使用しますが、Mongo 接続の数など多くのリソースを占有しません。
Python Python ソリューション:
(pymongo) [root@bj-redis-slave02-10-8-2-245 history]# python delete-pic.py > 2021-8.log &
(pymongo) [root@bj-redis-slave02-10-8-2-245 history]# tail -f 2021-8.log
4. 添付ファイル: コード:
#!/usr/bin/python
# -*- encoding: utf-8 -*-
import pymongo
import json
import os
from pymongo import MongoClient
from gridfs import GridFS
class GFS(object):
def __init__(self, file_db,file_table):
self.file_db = file_db
self.file_table = file_table
def createDB(self): #连接数据库,并创建文件数据库与数据表
client = MongoClient('10.8.2.237',30000)
db = client[self.file_db]
file_table = db[self.file_table]
return (db,file_table)
def insertFile(self,db,filePath,query): #将文件存入数据表
fs = GridFS(db,self.file_table)
if fs.exists(query):
print('已经存在该文件')
else:
with open(filePath,'rb') as fileObj:
data = fileObj.read()
ObjectId = fs.put(data,filename = filePath.split('/')[-1])
print(ObjectId)
fileObj.close()
return ObjectId
def getID(self,db,query,pic): #通过文件属性获取文件ID,ID为文件删除、文件读取做准备
try:
fs=GridFS(db, self.file_table)
ObjectId=fs.find_one(query)._id
msg=pic,'ObjectId',ObjectId
print (msg)
return ObjectId
except AttributeError as e: #AttributeError为错误类型,此种错误的类型赋值给变量e;当try与except之间的语句触发
# AttributeError错误时程序不会异常退出而是执行except AttributeError下面的内容
print("AttributeError错误,图片不存在:",e)
def remove(self,db,id): #文件数据库中数据的删除
fs = GridFS(db, self.file_table)
fs.delete(id) #只能是id
del_msg= id,'正在删除!!!'
print (del_msg)
def getFile(self,db,id): #获取文件属性,并读出二进制数据至内存
fs = GridFS(db, self.file_table)
gf=fs.get(id)
bdata=gf.read() #二进制数据
attri={
} #文件属性信息
attri['chunk_size']=gf.chunk_size
attri['length']=gf.length
attri["upload_date"] = gf.upload_date
attri["filename"] = gf.filename
attri['md5']=gf.md5
print(attri)
return (bdata, attri)
def Writ_log(self,File,msg):
f=open(File,'a')
f.write(msg)
f.close()
def listFile(self,db): #列出所有文件名
fs = GridFS(db, self.file_table)
gf = fs.list()
def findFile(self,db,file_table): #列出所有文件二进制数据
fs = GridFS(db, table)
for file in fs.find():
bdata=file.read()
def write_2_disk(self,bdata, attri): #将二进制数据存入磁盘
name = "get_"+attri['filename']
if name:
output = open(name, 'wb')
output.write(bdata)
output.close()
print("fetch image ok!")
if __name__=='__main__':
gfs=GFS('pics','fs')
(file_db,fileTable) = gfs.createDB() #创建数据库与数据表
dir_list = os.listdir('2021-8')
print (dir_list)
for filePath in dir_list:
filePath='2021-8/'+filePath
lines = open(filePath,'r').readlines()
for file in lines:
pic =file.splitlines()[0]
query = '{"filename": "%s"}' %(pic)
query = json.loads(query)
id=gfs.getID(file_db,query,pic)
gfs.remove(file_db,id) #删除数据库中文件
#filePath = '10.txt' #插入的文件
#query = {'filename': '745082993188.jpg'}
#id=gfs.getID(file_db,query,pic)
#gfs.remove(file_db,id) #删除数据库中文件
#id=gfs.insertFile(file_db,filePath,query) #插入文件
#(bdata,attri)=gfs.getFile(file_db,id) #查询并获取文件信息至内存
#gfs.write_2_disk(bdata,attri) #写入磁盘
#gfs.remove(file_db,id) #删除数据库中文件
参考:
pymongo には、mongo nosql の操作に関する多くのチュートリアルがあり、複数の Gridfs ファイル システムのアップロードとダウンロードに関する多くの紹介があります。しかし、gridfs の削除操作についてはあまり紹介されていません。中心となる重要な操作は、最初にファイルのファイル ID を取得し、次に、remove メソッドを使用してファイル ID を削除することです。(ファイルの削除メソッドはファイル ID のみを受け入れます)
公式: https://pymongo.readthedocs.io/en/stable/tutorial.html
Gridfs 削除公式: https://pymongo.readthedocs.io/en/stable/api/gridfs/index.html?highlight=delete#gridfs.GridFS.delete
https://blog.csdn.net/qq_30852577/article/details/84645693
https://blog.csdn.net/weiyuanke/article/details/7717476