pymongはmongogridfsファイルをバッチで削除します

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

おすすめ

転載: blog.csdn.net/weixin_43423965/article/details/128563115