膨大な数の画像を生成するプロジェクトがあります。最初は約1,000,000です。これらは大きな画像ではないので、最初はすべて1台のマシンに保存します。
これらの画像を効率的に保存するには、どのようにすすめますか? (現在NTFSファイルシステム)
命名スキームを検討しています...まず、すべての画像に1からの増分名が付けられます。これにより、後で必要に応じて画像を並べ替えて、別のフォルダに入れることができます。
より良い命名体系は何でしょう:
a/b/c/0 ... z/z/z/999
または
a/b/c/000 ... z/z/z/999
これについて何か考えはありますか?
データベースの代わりに通常のファイルシステムを使用することをお勧めします。ファイルシステムの使用はデータベースよりも簡単です。通常のツールを使用してファイルにアクセスできます。ファイルシステムはこのような用途向けに設計されています。NTFSはストレージシステムとして正常に機能するはずです。
データベースへの実際のパスを保存しないでください。画像のシーケンス番号をデータベースに保存し、シーケンス番号からパスを生成できる機能を追加することをお勧めします。例えば:
File path = generatePathFromSequenceNumber(sequenceNumber);
ディレクトリ構造をなんらかの方法で変更する必要がある場合は、処理が簡単です。おそらく、イメージを別の場所に移動する必要があるかもしれません。おそらくスペースが足りなくなり、一部のイメージをディスクAやディスクBに保存し始めます。データベース内のパスを変更するよりも、1つの関数を変更する方が簡単です。 。
私はディレクトリ構造を生成するためにこの種のアルゴリズムを使用します:
12345
-> 000000012345.jpg
000000012345
-> 000/000/012
123
のファイルの完全パスとファイル名は000/000/012/00000000012345.jpg
です。12345678901234
のファイルの場合、パスは123/456/789/12345678901234.jpg
になりますディレクトリ構造とファイルストレージについて考慮すべき事項:
私は2セント相当のマイナスのアドバイスをします。データベースを使用しないでください。
私は何年も画像保管データベースを扱ってきました。大きな(1 meg-> 1 gig)ファイル、頻繁に変更される、ファイルの複数のバージョン、かなり頻繁にアクセスされる。大きなファイルを保存する際に遭遇するデータベースの問題は対処が非常に退屈であり、書き込みやトランザクションの問題は面倒であり、主要な列車の破壊を引き起こす可能性のあるロックの問題に遭遇します。私はdbccスクリプトを作成し、バックアップからテーブルを復元する際に、通常の人が行うよりも多くの練習をしています 今まで 持ってる。
私がこれまでに使用した新しいシステムのほとんどは、ファイルストレージをファイルシステムにプッシュし、インデックス作成以外はデータベースに依存していました。ファイルシステムは、そのような悪用を行うように設計されており、拡張がはるかに簡単で、1つのエントリが破損してもファイルシステム全体が失われることはめったにありません。
これに対処する必要があるほとんどのサイトは、ファイルがフォルダに均等に分散されるようにするために、何らかのハッシュを使用していると思います。
したがって、次のようなファイルのハッシュがあるとします515d7eab9c29349e0cde90381ee8f810
これを次の場所に保存して、各フォルダ内のファイル数を少なくするために必要な深さのレベルを使用できます。\51\5d\7e\ab\9c\29\349e0cde90381ee8f810.jpg
私はこのアプローチが何度も取られるのを見てきました。これらのファイルハッシュを人間が読める名前にマップするためのデータベースと、他に保存する必要があるメタデータが必要です。しかし、このアプローチはかなりうまく拡張できます。ハッシュアドレススペースを複数のコンピューターやストレージプールなどに分散し始めることができます。
理想的には、特定のハードドライブのセットアップ、キャッシュ、使用可能なメモリなどがこれらの結果を変更する可能性があるため、さまざまな構造のランダムアクセス時間に対していくつかのテストを実行する必要があります。
ファイル名を制御できると想定すると、ディレクトリごとに1000のレベルでそれらを分割します。追加するディレクトリレベルが多いほど、書き込むiノードが増えるため、ここにプッシュプルがあります。
例えば。、
/ root/[0-99]/[0-99]/filename
注: http://technet.Microsoft.com/en-us/library/cc781134(WS.10).aspx には、NTFSセットアップの詳細があります。特に、「NTFSフォルダーで多数のファイル(300,000以上)を使用する場合は、パフォーマンスを向上させるために短いファイル名の生成を無効にしてください。特に、長いファイル名の最初の6文字が類似している場合」
また、不要なファイルシステム機能(たとえば、最終アクセス時間)を無効にすることも検討する必要があります。 http://www.pctools.com/guides/registry/detail/50/
何をするにしても、それらすべてを1つのディレクトリに保存しないでください。
これらの画像の名前の分布に応じて、画像の2番目の文字などのサブフォルダーの別のセットがある1文字の最上位フォルダーがあるディレクトリ構造を作成できます。
そう:
フォルダimg\a\b\c\d\e\f\g\
には、「abcdefg」で始まる画像などが含まれます。
必要な独自の適切な深さを導入できます。
このソリューションの優れた点は、ディレクトリ構造がハッシュテーブル/辞書のように効果的に機能することです。イメージファイル名を指定すると、そのディレクトリがわかり、ディレクトリを指定すると、そこに移動するイメージのサブセットがわかります。
400万枚の写真を保存できるフォトストアシステムがあります。データベースはメタデータにのみ使用し、すべての画像は逆ネーミングシステムを使用してファイルシステムに格納されます。フォルダー名はファイルの最後の桁から、最後の1からというように生成されます。例:000001234.jpgは4\3\2\1\000001234.jpgのようなディレクトリ構造に保存されます。
このスキームは、ディレクトリ構造全体を均等に満たすため、データベースのIDインデックスと非常にうまく機能します。
これらはファイルシステムに保存しますが、ファイル数がどれだけ速く増加するかによって異なります。これらのファイルはWebでホストされていますか?これらのファイルにアクセスするユーザーは何人ですか?これらは私があなたにもっと良い推薦を与えることができる前に答えられる必要がある質問です。 FacebookのHaystackも見てみます。画像の保存と提供には非常に優れたソリューションがあります。
また、ファイルシステムを選択する場合は、これらのファイルをディレクトリでパーティション化する必要があります。私はこの問題を見て解決策を提案しましたが、決して完璧な解決策ではありません。私はハッシュテーブルでパーティションを分割しています。ユーザーは、私の blog で詳細を読むことができます。
要は、DBにファイルパスを保存する必要はありません。説明した方法でファイルに名前が付けられている場合は、数値を格納するだけで済みます。次に、すでに説明した明確に定義されたストレージスキーマの1つを使用して、インデックスを数値として取得し、ディレクトリ構造をたどることでファイルを非常にすばやく見つけることができます。
新しいMS SQL 2008には、このようなケースを処理するための新しい機能があり、FILESTREAMと呼ばれています。見てください:
画像に一意の名前を付ける必要がありますか?これらの画像を生成するプロセスで、同じファイル名を複数回生成できますか?どのデバイスがファイル名を作成しているのかを知らずに言うのは難しいですが、デバイスは「リセット」されており、再起動すると、前回「リセット」されたときと同じようにイメージの名前が付けられます。
また、1か月の間に100万枚の画像をヒットするとします。その後はどうですか? これらの画像がファイルシステムを使い続ける速度はどれくらいですか?ある時点で上限に達し、約100万枚の画像で横ばいになるか、または今後も拡大し続けますか?そして、毎月成長しますか?
ファイルシステムの設計を月単位で開始してから、イメージ単位で開始していただけると思います。このようなディレクトリ構造に画像を保存することをお勧めします:
imgs\yyyy\mm\filename.ext
where: yyyy = 4 digit year
mm = 2 digit month
example: D:\imgs\2009\12\aaa0001.jpg
D:\imgs\2009\12\aaa0002.jpg
D:\imgs\2009\12\aaa0003.jpg
D:\imgs\2009\12\aaa0004.jpg
|
D:\imgs\2009\12\zzz9982.jpg
D:\imgs\2010\01\aaa0001.jpg (this is why I ask about uniqueness)
D:\imgs\2010\01\aab0001.jpg
セキュリティタイプの画像には、月、年、日でもよい。これがあなたのしていることかどうかはわかりませんが、10秒ごとに写真を撮るホームセキュリティカメラを使ってそれを行いました...このようにして、アプリケーションは特定の時間または画像が生成されたと思われる範囲までドリルダウンできます。または、年、月の代わりに-画像ファイル自体から派生できる他の「意味」はありますか?私が与えた日付の例以外のいくつかの他の記述子?
バイナリデータをDBに保存しません。そのようなことで良いパフォーマンス/運がなかった。 100万枚の画像でうまく機能すると想像してください。私はファイル名を保存します、それだけです。すべてがJPGになる場合は、拡張子を保存しないでください。ファイルのサーバー、ドライブ、パスなどへのポインターを格納するコントロールテーブルを作成します。これにより、これらの画像を別のボックスに移動しても、それらを見つけることができます。 画像にキーワードタグを付ける必要がありますか?もしそうなら、そのようなタグ付けを可能にする適切なテーブルを構築したいと思うでしょう。
あなた/他の人が私が返信している間にこれらのアイデアに対処した可能性があります。
さまざまなデバイスの状態を記録するために、1年の間に840万枚の画像を保存するプロジェクトに携わっています。最近の画像にアクセスする頻度が高くなり、アーカイブを掘り下げるように促す条件が発見されない限り、古い画像が検索されることはほとんどありません。
この使用法に基づく私の解決策は、画像を段階的に圧縮ファイルに圧縮することでした。画像はJPGで、それぞれ約20 KBであり、あまり圧縮されないため、Zip圧縮スキームはありません。これは単に、それらを1つのファイルシステムエントリに連結するために行われます。これは、ドライブからドライブへの移動、またはファイルのリストの検索に関して、速度の点でNTFSに大きく役立ちます。
1日以上経過した画像は、「毎日の」Zipに結合されます。 1か月より古いzipは、それぞれの「毎月」のzipに結合されます。そして最後に、1年以上何も必要なくなり、その結果削除されました。
このシステムは、ユーザーがファイルを(オペレーティングシステムまたは多数のクライアントアプリケーションを介して)参照でき、すべてにデバイス名とタイムスタンプに基づいて名前が付けられるため、うまく機能します。一般に、ユーザーはこれらの2つの情報を知っており、何百万もの画像のいずれかをすばやく見つけることができます。
これはおそらくあなたの特定の詳細とは関係がないと思いますが、共有したいと思いました。
これでゲームに遅れるかもしれません。しかし、1つの解決策(ユースケースに適合する場合)は、ファイル名のハッシュ化です。これは、ファイルの名前を使用して簡単に再現できるファイルパスを作成すると同時に、よく分散されたディレクトリ構造を作成する方法です。たとえば、パスとしてファイル名のハッシュコードのバイトを使用できます。
String fileName = "cat.gif";
int hash = fileName.hashCode();
int mask = 255;
int firstDir = hash & mask;
int secondDir = (hash >> 8) & mask;
これにより、パスは次のようになります。
/172/029/cat.gif
その後、cat.gif
アルゴリズムを再現することにより、ディレクトリ構造で。
ディレクトリ名としてHEXを使用するのは、int
値を変換するのと同じくらい簡単です。
String path = new StringBuilder(File.separator)
.append(String.format("%02x", firstDir))
.append(File.separator)
.append(String.format("%02x", secondDir)
.toString();
その結果:
/AC/1D/cat.gif
私は数年前にこれについての記事を書き、最近それをMediumに移動しました。詳細とサンプルコードがいくつかあります ファイル名のハッシュ:ハッシュされたディレクトリ構造の作成 。お役に立てれば!
災害復旧を検討していますか?
ここで提案されている解決策のいくつかは、ファイル名を変更することになります(物理ファイルが移動された場合、実際にどのファイルであるかを追跡できなくなります)。ファイルの場所のマスターリストが破損した場合に、小さなシェル、er、powershell、スクリプトで再生成できるように、一意の物理ファイル名を維持することをお勧めします;)
ここで読んだことから、これらのファイルはすべて1つのファイルシステムに格納されているように思えます。それらを複数のマシンの複数のファイルシステムに保存することを検討してください。リソースがある場合は、電源が失われて交換が2日間続く場合に備えて、2つの異なるマシンに各ファイルを保存するシステムを決定します。
マシン間またはファイルシステム間でファイルを移行するためにどのような手順を作成する必要があるかを検討します。ご使用のシステムでこれを実行する機能はライブであり、オンラインで使用することで、将来、かなりの頭痛を軽減できます。
増分番号カウンター(データベースID列?)がめちゃくちゃになる場合は、増分番号の代わりにGUIDを物理ファイル名として使用することを検討してください。
必要に応じて、Amazon S3などのCDNの使用を検討してください。
おそらく、作成日ベースの命名スキーム-ファイル名にすべての情報を含めるか、(後で閲覧するのに適しています)ディレクトリに分割します。画像を生成する頻度に応じて、次のことを考えることができます。
Year/Month/Day/Hour_Minute_Second.png
Year/Month/Day_Hour_Minute_Second.png
等。あなたは私のポイントを得る... =)
私はそのスケールで写真を提供していませんが、400MHzマシンで約25,000枚の写真を提供するための小さなギャラリーアプリを以前に作成しました。 512 MB RAM程度。いくつかの経験;
リレーショナルデータベースは絶対に避けてください。データベースは間違いなくデータの処理に優れていますが、そのような用途向けには設計されていません(ファイルシステムと呼ばれる、専用の階層型Key-Valueデータベースを用意しました)。私は直感以上のものはありませんが、非常に大きなblobをスローすると、DBキャッシュがウィンドウの外に出ることに賭けます。私の利用可能なハードウェアは小さなものでしたが、イメージルックアップでDBをまったく操作しなかったため、桁違いの速度が得られました。
ファイルシステムの動作を調査します。 ext3(または当時はext2でした-思い出せません)では、サブディレクトリとファイルを効率的に検索できる限界は約256マークでした。そのため、特定のフォルダには、その数のファイルとフォルダしかありません。再び、顕著なスピードアップ。 NTFSについては知りませんが、XFSのようなもの(私が覚えている限りBツリーを使用しています)は非常に高速です。
データを均等に分散します。上記で実験したところ、すべてのディレクトリにデータを均等に分散しようとしました(URLのMD5を実行し、それをディレクトリに使用しました。/1a/2b/1a2b...f.jpg
)。このようにすると、パフォーマンスの制限に達するまでに時間がかかります(このような大きなデータセットでは、ファイルシステムキャッシュは無効になります)。 (逆に、制限が早い段階で確認したい場合があります。次に、最初に利用可能なディレクトリにすべてをスローする必要があります。
私は日付ベースのフォルダ構造を作成する傾向があります。\year\month\day、およびファイル名にはタイムスタンプを使用します。必要に応じて、ミリ秒内に複数のイメージが作成されるほど高速にイメージを作成する場合は、タイムスタンプに追加のカウンターコンポーネントを含めることができます。命名の並べ替えに最上位から最下位のシーケンスを使用することで、検索と保守が簡単になります。例えばhhmmssmm [seq] .jpg
他のデータベースへの言及はありますが、投稿にはその言及はありません。いずれにせよ、この特定の点についての私の意見は、データベースまたはファイルシステムに固執することです。 2つを混ぜる必要がある場合は、注意してください。物事はより複雑になります。しかし、あなたがする必要があるかもしれません。 100万枚の写真をデータベースに保存することは、最良の考えではありません。
あなたは次の仕様に興味があるかもしれません、ほとんどのデジタルカメラはファイルストレージを管理するためにそれに従います: https://en.wikipedia.org/wiki/Camera_Image_File_Format
基本的に、000Olympus
などのフォルダーが作成され、そのフォルダーに写真が追加されます(例:DSC0000.RAW
)。ファイル名のカウンターがDSC9999.RAW
に達すると、新しいフォルダーが作成され(001Olympus
)、画像が再度追加され、カウンターがリセットされます。異なるプレフィックス(例:P_0000.RAW
)が使用される場合があります。
あるいは、ファイル名の一部に基づいてフォルダを作成することもできます(すでに何度か言及されています)。たとえば、写真の名前がIMG_A83743.JPG
の場合は、IMG_\A8\3\IMG_A83743.JPG
に保存します。実装は複雑ですが、ファイルを見つけやすくなります。
ファイルシステムによっては(これにはある程度の調査が必要です)、すべての画像を単一のフォルダーにダンプすることもできますが、私の経験では、これは通常パフォーマンスの問題を引き起こします。
私はzfsが大好きなため、zfsでテストを実行しました。圧縮した500gigパーティションがありました。私は50-100kファイルを生成し、ネストされたディレクトリ1/2/3/4/5/6/7/8(深さ5-8レベル)に配置するスクリプトを作成し、1週間実行できるようにしました。 (素晴らしいスクリプトではありませんでした。)ディスクがいっぱいになり、約2,500万のファイルができました。既知のパスを持つ1つのファイルへのアクセスは瞬時に行われました。既知のパスを持つディレクトリを一覧表示するのは簡単でした。
ただし、ファイルのリストの数を(findを介して)取得するには68時間かかりました。
また、1つのディレクトリに多数のファイルを置いてテストを実行しました。停止する前に、1つのディレクトリに最大で約370万個のファイルを取得しました。カウントを取得するためにディレクトリをリストするのに約5分かかりました。そのディレクトリ内のすべてのファイルを削除するには、20時間かかりました。しかし、ファイルの検索とアクセスは瞬時に行われました。
Windowsを使用している場合、exFatファイルシステムではどうでしょうか
http://msdn.Microsoft.com/en-us/library/aa914353.aspx
メディアファイルの保存を念頭に置いて設計され、現在利用可能です。
それらすべてがすぐに必要でなく、オンザフライで生成でき、これらが小さなイメージである場合、イメージジェネレーターの上にLRUメモリまたはディスクキャッシュを実装しないのはなぜですか?
これはストレージからあなたを救うことができ、memから提供されるホットなイメージを保持できますか?
多数からパスを生成するクリーンな方法は、簡単にそれを16進数に変換してから分割することです!
例えば 1099496034834
> 0xFFFF1212
> FF/FF/12/12
public string GeneratePath(long val)
{
string hex = val.ToString("X");
hex=hex.PadLeft(10, '0');
string path="";
for(int i=0; i<hex.Length; i+=2 )
{
path += hex.Substring(i,2);
if(i+2<hex.Length)
path+="/";
}
return path;
}
保存と読み込み:
public long Store(Stream doc)
{
var newId = getNewId();
var fullpath = GeneratePath(newId)
// store into fullpath
return newId;
}
public Stream Load(long id)
{
var fullpath = GeneratePath(newId)
var stream = ...
return stream;
}
完全なソースコード: https://github.com/acrobit/AcroFS
ZFS(Sunのファイルシステム、ボリュームマネージャ)を確認することをお勧めします。