2016-02-23 103 views
1

背景使用Spring批量读取文件,并写入地图

我是相当新的Spring Batch的,并具有以下要求:

  1. 读取一个文件的百万记录的minumum (CSV,管道分隔符等)
  2. 将文件中的每一行加载到一个Map with key作为第一列,并将值作为域对象/ POJO加载。

据我所知,Spring批处理有一种称为面向块的处理,其中一个配置读取器,处理器和一个写入器来处理由commit-interval支配的一定数量的记录。这可以进一步使用读者的任务执行程序或通过分区添加另一层多线程进行扩展。

问题

如在2点以上解释,我想我的文件加载到地图。为了讨论的缘故,可以说我实现了下面的ItemWriter,它将块聚合到一个Map中。

public class MapItemWriter implements ItemWriter<SomePOJO> { 

    private Map<String, SomePOJO> somePojoMap; 

    public MapItemWriter() { 
     System.out.println("Writer created "); 
     somePojoMap= new ConcurrentHashMap<String, SomePOJO>(); 
    } 

    public void write(List<? extends SomePOJO> item) throws Exception { 
     if (item != null && item.size() > 0) { 
      for (SomePOJO data : item) { 
       String uniqueId = data.Id(); 
       somePojoMap.put(uniqueId, data); 
      } 
     } 
    } 

    public Map<String, SomePojo> getSomePojoMap() { 
     return somePojoMap; 
    } 
} 

因为我有机会到我的ItemWriter豆,我可以再打getSomePojoMap得到汇总图在我的档案记录;然而,在ItemWriter中持有像这样的Map并不觉得这是最好的方式。另一个问题是,使用ConcurrentHashMap可能会降低性能,但我没有看到任何其他方式可以以线程安全的方式将文件聚合到Map中。

有没有更好的方法来将我的文件聚合到一个Map中,而不是在我的writer中保存一个Map并使用ConcurrentHashMap?

+0

为什么要将数据加载到地图中?地图填充后会发生什么? –

+0

@MichaelPralow我们有一个遗留系统,它将文件中的数据加载到一个Map中(每个文件一个)。我们想用Spring批次替换数据加载层。这些映射用于汇聚层,该汇聚层将来自不同映射的数据聚合为在另一个系统侦听的JMS队列上发送的主对象。我们不想更改聚合层,因为这意味着要修改整个遗留系统。我们希望提高数据加载性能。如果我们保持与汇聚层的接口相同,它可以继续工作,就好像没有任何变化。 – CKing

回答

1

或多或少。你可以做一些小的改进,比如把地图放在一个单独的bean中,这样可以让你为writer bean和地图创建不同的生命周期,并且也可以将地图的读者与作者分开。例如,你可以把地图放在一个作业范围的bean中,并且仍然让作者成为一个单例。

如果你的工作被划分为多个线程(我假设你不希望地图在作业之间共享),那么你只需要一个ConcurrentHashMap

+0

谢谢。你是对的。 “Map”不是跨作业共享的。另外,读取文件的步骤将使用Tasklet与TaskExecutor,或者我甚至可以将文件分割为磁盘上的物理分区。我的工作的最终结果将是包含文件内容的地图。我的工作只有一个步骤,即读取文件并加载到“Map”。我在互联网上遇到的大多数例子都使用作者写入文件或数据库。我觉得我正在使用ItemWriter来处理它没有设计的东西。 Spring Batch的用户会对此产生不满吗? – CKing

+0

@CKing我不知道我是否可以为一位资深的Spring Batch用户发言;我可以说,你并没有使用Spring Batch分块步骤的设计目的:可以一次一个事务地处理大块数据,并可选择重试,跳过和重新启动。只要将以前的块保存在内存中,并且您的作者的操作不能回滚,则无法一次有效地处理块。但第一个特点似乎是由于您的遗留要求,第二个特点可能并不是真的,因为您的作家永远不会失败。 – Artefacto

+0

这正是我的担心。使用框架来实现它不是为了设计的。我的要求不适合典型的Spring批处理用例。我主要是选择Spring批处理,因为它是现成的平面文件解析API和缩放选项。如果我的数据集将来会增加(通常会发生这种情况),那么我可以使用Spring批处理提供的各种选项来扩展我的应用程序。如果读取可伸缩性是我唯一的目标,您是否知道我应该关注的其他框架? – CKing

0

为什么不使用File Item Writer。

我假设这张地图应该写入一个文件。可能是一个平面文件(txt)

如果是这种情况,请尝试使用FlatFileItemWriter。如果您需要将这些数据写入xml文件,您可以使用StaxEventItemWriter

即使您不需要将数据写入文件(在批处理结束时只需要映射)。我认为将数据写入文件并在之后从文件中读取整个地图将会“更便宜”。将作图保存在作业范围内意味着该对象将在每个块中保留在db中,并且将在每个块上从db中检索,这相当昂贵的操作。

+0

如果我将数据从文件加载到'Map'中,然后将其写回到文件中,然后在需要时再次将其加载到Map中,我是不是会绕圈转圈? – CKing

+0

如果你对提取的数据没有逻辑,我认为你不会享受阅读块效益。仍然春天批次有更多的功能(重试,听众等),但读取卡盘和保存地图为作业范围对象将是昂贵的,不值得。 –

+0

我给了它一些想法,你说的是正确的。如果我只是将数据加载到“Map”中,则读入块没有任何好处;然而,事实并非如此。我将对这些数据应用一些过滤器,并删除那些不符合过滤条件的记录。就像一个数据库 - where子句。 – CKing