Javaでアプリケーションを開発し、REST APIを介してCSVからオンラインデータベースにレコードを解析およびアップロードします。
各CSVファイルに重複するレコードがないことは確かですが、各CSVファイルが1度しか処理されていないことを確認できないため(*以下の説明を参照)、挿入する前に重複がないか確認する必要があります。
[明確化]各CSVファイルが一度しか処理されていないことを確認してソリューションを実装することはできません。 CSVファイルには、銀行からダウンロードされた銀行取引レコードが含まれています。したがって、個々のCSVファイルには重複が含まれていないことがわかります。ただし、同じ日付範囲、または重複する日付範囲などについて、複数のCSVファイルをダウンロードできます。そのため、ファイルレベルではなくトランザクションレベルで重複をチェックする必要があります。
残念ながら、私はバックエンドデータベースを制御できず、API経由で利用可能なメソッドしか使用できません。これは、SQLを使用する通常のソリューション(例: この質問 )は適切ではないことを意味します。
APIから利用できるメソッド( http://help.moneytrackin.com/index.php/REST_API ):
listTransactions
editTransaction
insertTransaction
利用できるがおそらく関連しない方法:
listProjects
listWriteProjects
getBalance
getTags
新しいプロジェクト
deleteProject
listTagTransactions
deleteTransaction
listCurrencies
userData
これは巨大なデータベースではありません。4つの列と数千のレコードのみです。
私の唯一のオプションは、挿入される各レコードを反復処理し、それをデータベースの各レコードと比較することです:
get ListOfRecordsInDb from database using listRecords(). Store in HashMap,
local database or similar data structure??
for each record to be inserted,
iterate over ListOfRecordsInDb, checking none of them match
the record to be inserted
if no match found, insert record
これは非常に非効率的です。他のオプションはありますか?そうでない場合、Javaを使用して何千ものレコードを比較する最も効率的な方法は何ですか?
コメント/質問への回答:
すでに存在するトランザクションでinsertTransactionを呼び出すとどうなりますか?それを複製しますか、それとも失敗しますか?
トランザクションは複製として正常に挿入されました
CSVファイルに「id」列はありますか?
いいえ。利用可能な列は、日付、説明、金額、残高です。これらの組み合わせにより各レコードが一意になるため、これらに基づいてIDを作成できる可能性があります。
ListRecords()はページ分割を許可しますか、それともすべてのレコードのみを返すことができますか?
XML形式でレコードを返すだけです。
各CSVファイルが1度だけ処理されたことを確認できません...
これを最初に処理することで、問題を解決しようとする場合があります。私がこれを正しく行っている場合、問題の核心は個々の重複トランザクションではないようです(「各CSVファイルに重複レコードがないことは確かです」からです)が、重複処理は防止しますperファイル。
したがって、ある種の状態ロジックをJavaアプリケーションに追加することを検討できます。Java$ ===チェックサムの計算と保存によってファイルが処理されたかどうかがわかります。例 そのMD5ハッシュ 。一致するチェックサムを取得すると、ファイルが以前に処理された可能性が高いことがわかります。行数や各ファイルの他の特定の一意の識別子を検査するなど、さらに検証を実行できます。
このアイデアをさらに拡張して、同じトランザクションが異なるCSVファイルに現れる可能性がある場合、データベーススキーマを更新して重複レコードを適切に処理する以外の唯一のオプションは、処理されたすべてのトランザクションをローカルにJavaアプリケーション。アプリケーションの複数のインスタンスが存在する場合(同じコンピューター上、またはネットワーク全体)には、これを処理するためのさらに別の集中型データベース、またはいくつかの分散データグリッドが必要です。 ..それまでに、既存のデータベーススキーマをimproveするためのより良いオプションは、まだ図面に戻っています。
edit
物事をひっくり返すために、検討すべき他の考慮事項 、データベーススキーマを変更して重複を適切に処理する場合全体don't-even-think-about-itnigh不可能、 Javaアプリケーションが常に処理する必要のあるデータの量、およびデータベースとアプリケーション間の接続の速度を評価することです。
下端では、アプリケーションがファイルごとに10レコードのみを処理し、1時間に1ファイルを平均するとします。ネットワーク接続は非常に良好であり、ローカルにホストされているデータベースにアクセスするのとほぼ同じです。この場合、すべてのレコードを照会する必要があることによるパフォーマンスへの影響はそれほどないと思います。
極端な場合、アプリケーションは10秒ごとに数千行のトランザクションファイルを読み取ることが予想され、ネットワーク接続は非常に悪いです。たとえば、すべてのレコードをクエリするのに1分かかります。この場合、ファイルを迅速に処理することについてより多くの懸念があり、これがおそらくデータベーススキーマの変更を提案できる方法です。 :)
それで、ローエンドのケースですべてがうまくいっていると仮定して、複製のために比較的大きなデータセットを小さな入力セットと比較する効率的な方法は何でしょうか? HashSet
に入れるXMLペイロードをマーシャリングすることをお勧めします。また、hashCode()
メソッドとequals()
メソッドが適切に実装されたTransaction
ドメインクラスがあることを願っています。 A Java 8の潜在的なソリューションは次のようになります:
// assuming your database records are marshalled into currentSet
inputSet.stream().filter(v -> !currentSet.contains(v))
.forEach( /* these are the new records to send to the database */);
また、部屋の象:同時挿入。何かありますか?もしそうなら、それをどのように扱うつもりですか?
あなたはトリッキーな入力とトリッキーなバックエンドで、両方向に圧迫されています。理想的な世界では、これらの制約のいくつかに挑戦するでしょうが、私はあなたがどこにも得られないという印象を受けます。
あなたが説明するアルゴリズムはあなたの唯一のオプションのように聞こえますが、少し改善できると思います。
数千行しかないので、誰かがCSVをアップロードするたびにlistTransactionsを呼び出すことは許容できると思います。データベースが大きい場合は、独自のデータベースを作成することを検討する必要があります。これは、重複を回避する目的でのみRESTバックエンドをミラー化したものです。
あまり関係がありませんが、トランザクションにIDがない場合にREST APIがeditTransactionを持つことができる方法がわかりません。
編集-OK、CSVファイルにIDはありませんが、バックエンドRESTサービスにはIDがあります。
REST APIについてだとおっしゃっていましたが、APIを呼び出すたびにネットワークトラフィックが発生し、レイテンシと転送時間がかかると考えてください。APIへの呼び出しが少ないと思います。作成する(結果をメモリに保存して検索する)ほど良いでしょう。
ただし、APIを使用する場合、常に選択できるわけではありません。API自体が適切に設計されていない場合や、意図したような目的で設計されていない場合は、述べたとおりに選択するしかありません。
また、リモートサービス(REST API)を多くのユーザーが同時に使用できることを考慮してください。つまり、すべての結果をメモリまたはローカルDBにロードして後で処理すると、リモートデータがその間に変更されたために問題が発生する可能性があります。
私はあなたの質問に対する正しい答えではないと思います。適切な答えは、最初に利用可能なAPIコールとその入力と出力を十分に文書化している場合にのみ与えられると思いますが、これらのいくつかから利益を得ることができます。ヒント、私は願っています。