0

私はデータ マイナーなので、生データをさまざまな方法で変換して、予測モデルによる消費を可能にすることに多くの時間を費やしています。たとえば、特定の形式でファイルを読み取り、トークン化し、グラム化し、何らかの数値表現に射影します。何年にもわたって、考えられるほとんどのデータ処理タスクを実行するための豊富なメソッドのセットを開発してきましたが、最も基本的な方法を除いて、これらのコンポーネントを構成する良い方法はありません。通常、私が行うことはたくさんあります。特定のタスクに依存するソース コード内の特定のメソッドへの呼び出し。私は今、自分のライブラリをより良いものにリファクタリングしようとしていますが、これが何であるかはよくわかりません.

私の現在の考えは、関数オブジェクトのリストを持ち、それぞれがいくつかのメソッド (たとえば、operate( ... ) ) を定義し、順番に呼び出され、それぞれが参照によってデータフローの内容を処理するか、出力を消費することです。前の関数オブジェクト。これは私が望むものに近いですが、入力と出力されるデータの型が異なるため、ジェネリックを使用することは非常に困難になります。上記の例を使用するには、次のようなデータを処理するこの「パイプライン」を介して何かを渡したいと思います:

input: string filename
filename -> collection of strings
collection<string> -> (stemming, stopword removal) -> collection of strings
collection<string> -> (tokenize) -> collection of string arrays
collection<string[]> -> (gram-ify) -> augment individual token strings with n-grams -> collection of string arrays
collection<string[]> -> projection into numeric vectors -> collection< double[] >

これは単純な例ですが、このようなコンポーネントが数百個あり、それらをデータ フローに追加したいとします。これは、設定が簡単な要件を満たしています。いくつかの yaml ファイルを読み取ってこれを構築するパイプライン ファクトリを簡単に構築できます。しかし、コンポーネントの設計パターンにしばらく悩まされていましたか? 適切なインターフェースはどのように見えますか? ここで物事を行う唯一の簡単な方法は、オブジェクトを渡して、本質的にオブジェクトを廃止し(またはオブジェクトをメンバー変数として持つコンテキストオブジェクトを渡して)、入力時の互換性をチェックし、ランタイム例外をスローすることです。 . どちらのオプションも同じように悪いようです。しかし、私はここで本当に素晴らしく柔軟なシステムに近づいているように感じます. これをフェンス越しに押すのを手伝ってくれませんか?

4

3 に答える 3

1

ライブラリを結び付けるためのより機敏なツールが良いアプローチになると思います。たとえば、新しい動的言語の 1 つが最適です。

Clojure は、map、pmap、reduce filter などのすべてが組み込まれているツールに最適です。Clojure のコレクションはすべて、java.util Collection ライブラリのインターフェースを実装しているため、より高いレベルの Clojure 関数を既存の Java コードに適用できます。また、Clojure データ構造を Java コードに直接渡すこともできます (Java コードが変更を想定していない場合に限ります)。

言語の軽量で動的な性質により、多くのオーバーヘッドも発生せずに、物事をすばやく簡単にまとめることができます。

于 2011-11-10T02:23:00.403 に答える
1

私はあなたの例を文字通り読みすぎているかもしれません。つまり、この解決策は実際の問題には適用できない可能性があります。

public interface Interface1 {
  public List<String> operate(List<String> list);
}

public interface InterfaceBridge {
  public List<List<String>> operate(List<String> list);
}

public interface Interface2 {
  public List<List<String>> operate(List<List<String>> list);
}

明らかに、より適切なインターフェイス名を選択する必要があります。次に、それらを次のように構成できます。

public class Interface1Composite implements Interface1 {
  List<Interface1> components = new ArrayList<>();

  public Interface1Composite(Interface1... components) {
    for (Interface1 i1 : components)
      this.components.add(i1);
  }

  @Override 
  public List<String> operate(List<String> list) {
    for (Interface1 i1 : components)
      list = i1.operate(list);
    return list;
  }

私はそれがあなたがすでにやっていることのほとんどだと思います。ジェネリックを使用する代わりに、3 種類のインターフェイスを使用することで単純化しました。しかし、先に述べたように、それをあなたの問題に適用できるかどうかはわかりません。

于 2011-11-10T03:05:04.147 に答える
1

Apache Foundation には、パイプラインhttps://commons.apache.org/sandbox/pipeline/というプロジェクトがあります。多分それは役に立つかもしれません。そこにはパイプラインベースのプロジェクトがもっとあると思いました。そのサイトをブラウズすると便利かもしれません。

于 2011-11-10T02:14:20.170 に答える