Java模式:用于数据挖掘任务的工程数据流

时间:2011-11-10 02:07:13

标签: java design-patterns data-mining chain-of-responsibility

我是一名数据挖掘者,因此,我花了很多时间以各种方式转换原始数据,以便通过预测模型实现消费。例如,以某种格式读取文件,tokenize,gram-ify,并将项目转换为某种数字表示形式。多年来,我已经开发了一套丰富的方法来完成我能想到的大部分数据处理任务,但是我没有一个很好的方法来配置这些组件,除了最基本的方式 - 通常我做的很多调用源代码中依赖于特定任务的特定方法。我现在正在尝试将我的库重构为更好的东西,但我不太确定这是什么。

我目前的想法是,有一个函数对象列表,每个函数对象定义一些按顺序调用的方法(比如,操作(...)),每个方法都通过引用处理某些数据流的内容,或者消耗前一个函数对象的输出。这接近我想要的,但由于输入和输出的数据类型会有所不同,因此使用泛型变得非常困难。要使用上面的例子,我想通过这个处理数据的“管道”传递一些东西,如:

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[] >

这是一个简单的例子,但想象我有100个这样的组件,我想将它们添加到某些数据流中。这符合我易于配置的要求 - 我可以轻松地构建一个管道工厂,读取一些yaml文件并构建它。然而,组件的设计模式已经让我感到困惑了一段时间?适当的界面是什么样的?似乎在这里做事的唯一简单方法是让对象被传递,基本上取消对象(或者让一些上下文对象被传递,其中有一个Object作为成员变量),然后检查输入的兼容性,抛出运行时异常。两种选择看起来同样糟糕。但是,我觉得我在这里接近一个非常好的和灵活的系统。你能帮助我把它推到篱笆上吗?

3 个答案:

答案 0 :(得分:1)

apache基金会有一个名为pipelines https://commons.apache.org/sandbox/pipeline/的项目。也许它可以有用。我认为那里有更多基于管道的项目。浏览该网站可能很有用。

答案 1 :(得分:1)

我认为将图书馆绑在一起的更灵活的工具将是一个很好的方法。例如其中一种新的动态语言对此非常有用。

Clojure非常适合使用map,pmap,reduce filter等工具.Clojure的集合都实现了java.util集合库的接口,因此您可以将更高级别的Clojure函数应用于现有的Java代码,或者你也可以将Clojure数据结构直接传递给你的java代码(只要Java代码不希望修改它)。

语言的轻量级和动态性使得很容易将事情快速整合在一起,而且不会产生很多开销。

答案 2 :(得分: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种类型的接口,而不是尝试使用泛型。但正如我先前所说,我不知道你是否可以将其应用于你的问题。