如何处理大数据文件+录入数据

楼主喜欢用Java应对各种小需求,以此提高工作效率。

客户在集群上提供了一份.sql文件,有2个多G,用vim等编辑器打不开,只能less一部分,而且内容有乱码(中文部分,也不清楚该份文件的编码格式)——改一下vim的字符集配置就可以解决。
下载文件到本地,尝试用notepad++打开,提示“File is to be opened by Notepate++”;用MySQL Workbench打开,出现卡死。
使用文件分割器,对其进行分割。把文件拆分成15等份,每份150MB。
通过less可以看到建表语句,为oracle,改成postgresql版,并建好表。打开1.zg,把insert into之外的语句删掉后,用Navicat for PostgreSQL工具运行sql,出现字符集错误。
这里写图片描述

以下为数据样式示例:

insert into TB_IMSI_PARAM (NUM, IMSI, SIMNO, COST, PWD, MONTHFEE, EXPDATE, REMARK, CALLFEE, CALLEDFEE, GROUP_ID, GROUP_SHORT_NUM, SHORTNUM_FEE, CONF_FEE, IN_DATE, CARD_TYPE, MOD_DATE, IS_LONG_CARD, SMS_MOFEE, PUKCODE, ACTIVECODE, WIFI_MOFEE, AGENTCODE, SALE_PRICE, UPDATE_TIME, PRODUCT_ID)
values ('GD005', '460018172970051', '8986010712769238551', 2400, '123456', 0, 7, '皇岗集散中心(动)08.01.31-30', 2500, 2501, 57440, '1012', null, null, null, 30, to_date('27-06-2008 10:38:50', 'dd-mm-yyyy hh24:mi:ss'), null, 2013, null, null, 27, 'AYaGD005', null, null, 32);
insert into TB_IMSI_PARAM (NUM, IMSI, SIMNO, COST, PWD, MONTHFEE, EXPDATE, REMARK, CALLFEE, CALLEDFEE, GROUP_ID, GROUP_SHORT_NUM, SHORTNUM_FEE, CONF_FEE, IN_DATE, CARD_TYPE, MOD_DATE, IS_LONG_CARD, SMS_MOFEE, PUKCODE, ACTIVECODE, WIFI_MOFEE, AGENTCODE, SALE_PRICE, UPDATE_TIME, PRODUCT_ID)
values ('GD005', '460018172966280', '8986010712769234780', 2400, '123456', 0, 7, '集散中心(动)08.1.9-30', 2500, 2501, 57420, '0034', 0, 0, null, 30, to_date('27-06-2008 10:38:50', 'dd-mm-yyyy hh24:mi:ss'), null, 2013, null, null, 27, 'AYaGD005', null, null, 32);

我们可以发现文件中携带to_date('27-06-2008 10:38:50', 'dd-mm-yyyy hh24:mi:ss')函数,该函数在mysql中没找到,但是postgresql有,所以我们没有必要花大幅功力去切割这个函数。
在实践中,想要对每个文件进行insert into table values(...),values(...)....
最后证实在values中有嵌入函数时,是不能采用该策略的,所以该部分代码不贴。
同时,大家都知道,用oracle工具导出文件时,会有如下:

commit;
prompt 10000 records committed…
commit;
prompt 20000 records committed…
……

这些语句要记得处理。切割并不能保证每份文件都是完整的,所以sql语句的不完整只会在头和尾。有如下几种情况:


1.zg 尾:insert into TB_IMSI_PARAM (NUM, IMSI, SIMNO, COST, PWD, MONTHFEE, EXPDATE, REMARK, CALLFEE, CALLEDFEE, GROUP_ID, GROUP_SHORT_NUM,

2.zg 头:SHORTNUM_FEE, CONF_FEE, IN_DATE, CARD_TYPE, MOD_DATE, IS_LONG_CARD, SMS_MOFEE, PUKCODE, ACTIVECODE, WIFI_MOFEE, AGENTCODE, SALE_PRICE, UPDATE_TIME, PRODUCT_ID)
values (‘GD005’, ‘460018172966280’, ‘8986010712769234780’, 2400, ‘123456’, 0, 7, ‘集散中心(动)08.1.9-30’, 2500, 2501, 57420, ‘0034’, 0, 0, null, 30, to_date(‘27-06-2008 10:38:50’, ‘dd-mm-yyyy hh24:mi:ss’), null, 2013, null, null, 27, ‘AYaGD005’, null, null, 32);


1.zg 尾:values (‘GD005’, ‘460018172966280’, ‘8986010712769234780’, 2400, ‘123456’, 0, 7, ‘集散

2.zg 头:中心(动)08.1.9-30’, 2500, 2501, 57420, ‘0034’, 0, 0, null, 30, to_date(‘27-06-2008 10:38:50’, ‘dd-mm-yyyy hh24:mi:ss’), null, 2013, null, null, 27, ‘AYaGD005’, null, null, 32);


1.zg 尾:insert into TB_IMSI_PARAM (NUM, IMSI, SIMNO, COST, PWD, MONTHFEE, EXPDATE, REMARK, CALLFEE, CALLEDFEE, GROUP_ID, GROUP_SHORT_NUM, SHORTNUM_FEE, CONF_FEE, IN_DATE, CARD_TYPE, MOD_DATE, IS_LONG_CARD, SMS_MOFEE, PUKCODE, ACTIVECODE, WIFI_MOFEE, AGENTCODE, SALE_PRICE, UPDATE_TIME, PRODUCT_ID)

2.zg 头:values (‘GD005’, ‘460018172966280’, ‘8986010712769234780’, 2400, ‘123456’, 0, 7, ‘集散中心(动)08.1.9-30’, 2500, 2501, 57420, ‘0034’, 0, 0, null, 30, to_date(‘27-06-2008 10:38:50’, ‘dd-mm-yyyy hh24:mi:ss’), null, 2013, null, null, 27, ‘AYaGD005’, null, null, 32);


编码如下:

package com.sibat.uhuibao;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Collections;
import java.util.List;

import com.zh.zsr.FilePath;
/**
 * 
 * @author nanphonfy
 */
public class BigSQLFinal {
    public static void main(String[] args) throws IOException {
        String readFile = "C:\\Users\\sibat\\Desktop\\1";//把15份分割文件放在该目录
        String writeFile = "C:\\Users\\sibat\\Desktop\\2\\";//把处理后的文件放在该目录
        String errorFile = "C:\\Users\\sibat\\Desktop\\3\\";//把处理的错误文件放在这边,即error.sql

        String line = "";
        FilePath fp = new FilePath();
        List<String> readPath = fp.getFiles(readFile);

        Collections.sort(readPath);

        for (String p : readPath) {
            System.out.println(p);
        }

        FileInputStream fis = null;
        InputStreamReader isw = null;
        BufferedReader br = null;// 把filewriter的写法写成FileOutputStream形式
        int count = 0;

        FileOutputStream efos = new FileOutputStream(errorFile + "error.sql");
        OutputStreamWriter eosw = new OutputStreamWriter(efos, "UTF-8");
        BufferedWriter ebw = new BufferedWriter(eosw);// 把filewriter的写法写成FileOutputStream形式
        for (String path : readPath) {
            String arr[] = path.split("\\\\");// 为了得到文件名
            int length = arr.length;
            fis = new FileInputStream(path);
            isw = new InputStreamReader(fis, "GBK");//客户给的文件是GBK的
            br = new BufferedReader(isw);// 把filewriter的写法写成FileOutputStream形式
            String name = arr[length - 1].replace(".zg", "") + ".sql";
            FileOutputStream fos = new FileOutputStream(writeFile + name);
            OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");//数据库是设为UTF-8的,所以写入的时候要从GBK转码
            BufferedWriter bw = new BufferedWriter(osw);// 把filewriter的写法写成FileOutputStream形式

            long a = System.currentTimeMillis();
            int num = 0;// 第一行
            boolean flag = false;// 用来标记第一行是否完整,如果不完整,当第二行为values时,要存入错误文件
            while ((line = br.readLine()) != null) {
                if (line.isEmpty())
                    continue;

                if (num == 1) {
                    if (flag == true) {
                        if (line.contains("insert into TB_IMSI_PARAM (") && line.contains("PRODUCT_ID")) {
                            bw.write(line);
                            bw.newLine();
                            bw.flush();
                            num++;
                            continue;
                        } else {
                            ebw.write(line);
                            ebw.newLine();
                            ebw.flush();
                            flag = false;
                            num++;
                            continue;
                        }
                    }
                }

                if (num == 0) {
                    if (line.contains("values (") && line.contains(");")) {
                        ebw.write(line);
                        ebw.newLine();
                        ebw.flush();
                        num++;
                        continue;
                    } else if (line.contains("insert into TB_IMSI_PARAM (") && line.contains("PRODUCT_ID")) {
                        bw.write(line);
                        bw.newLine();
                        bw.flush();
                        num++;
                    } else {// 包括残缺,所以第二行可能为insert
                        ebw.write(line);
                        ebw.newLine();
                        ebw.flush();
                        flag = true;
                        num++;
                    }
                } else if ((line.contains("insert into TB_IMSI_PARAM (") && line.contains("PRODUCT_ID"))
                        || (line.contains("values (") && line.contains(");"))) {
                    bw.write(line);
                    bw.newLine();
                    bw.flush();
                    num++;
                } else {
                    if (line.contains("commit;") || line.contains("records committed..."))
                        continue;
                    ebw.write(line);
                    ebw.newLine();
                    ebw.flush();
                    num++;
                    // System.out.println(line);
                }
            }
            ebw.write("=====" + path + "=====\n\n");
            long b = System.currentTimeMillis();
            System.out.println(name + "文件耗时:" + (b - a) + "\n");
        }
    }
}

处理完后,可以用gvim 对检查各个文件的头尾。确保无误之后,就可以运行sql了。因为在Navicat for PostgreSQL工具不支持批量运行sql,每次都要运行完再运行下一个,效率不高。如何批量运行,代码如下:


package com.sibat.uhuibao;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.Statement;
import java.util.LinkedList;
import java.util.List;

import com.sibat.uhuibao.util.DBUtil;
import com.zh.zsr.FilePath;

/**
 * 读取 SQL 脚本并执行
 * 
 * @author nanphonfy
 */
public class SqlFileExecutor {

    /**
     * 传入连接来执行 SQL 脚本文件
     * 
     * @param conn
     *            传入数据库连接
     * @param sqlFile
     *            SQL 脚本文件
     * @throws Exception
     */
    public void execute(Connection conn, String sqlFile) throws Exception {
        FileInputStream fis = null;
        InputStreamReader isw = null;
        BufferedReader br = null;// 把filewriter的写法写成FileOutputStream形式
        fis = new FileInputStream(sqlFile);
        isw = new InputStreamReader(fis, "UTF-8");
        br = new BufferedReader(isw);// 把filewriter的写法写成FileOutputStream形式

        String line = null;
        long a = System.currentTimeMillis();
        int num = 0;
        String tmp = null;
        List<String> sqlList = new LinkedList<>();//因为路径是存放在这里面的,所以内存会被撑爆
        while ((line = br.readLine()) != null) {
            num++;
            if (num == 1) {
                tmp = line;
            }
            if (num == 2) {
                num = 0;
                tmp = tmp.concat(line);
                sqlList.add(tmp);
            }
        }
        Statement stmt = null;
        stmt = conn.createStatement();
        for (String sql : sqlList) {
            stmt.addBatch(sql);
        }
        stmt.executeBatch();
        System.out.println(sqlFile + "执行成功!!!!");
    }

    public static void main(String[] args) throws Exception {
        // List<String> sqlList = new SqlFileExecutor().loadSql(args[0]);
        // System.out.println("size:" + sqlList.size());
        // for (String sql : sqlList) {
        // System.out.println(sql);
        // }
        SqlFileExecutor executor = new SqlFileExecutor();
        String readFile = "C:\\Users\\sibat\\Desktop\\整理:final";//确保可以执行成功的文件
        FilePath fp = new FilePath();
        List<String> readPath = fp.getFiles(readFile);
        Connection conn = DBUtil.getConnection();

        for (String path : readPath) {
            executor.execute(conn, path);
        }

    }
}

FilesUtil.java

package com.sibat.uhuibao.util;

import java.io.File;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * JAVA遍历一个文件夹中的所有文件
 * 
 * @author nanphonfy
 * @time 2016年8月23日 下午3:34:18
 */
public class FilesUtil {
    private List<String> absolutePaths = new LinkedList<>();

    /*
     * 通过递归得到某一路径下所有的目录及其文件
     */
    public List<String> getFiles(String filePath) {

        File root = new File(filePath);
        File[] files = root.listFiles();
        for (File file : files) {
            if (file.isDirectory()) {
                getFiles(file.getAbsolutePath());
            } else {
                if (!file.getAbsolutePath().toString().contains("_SUCCESS"))
                    absolutePaths.add(file.getAbsolutePath().toString());
            }
        }
        return absolutePaths;
    }
}

DBUtil.java

package com.sibat.uhuibao.util;

import java.sql.SQLException;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
/**
 * 
 * @author nanphonfy
 */
public class DBUtil {

    private static DataSource dataSource = null;// 数据源一份就可以了,所以用static

    static {
        // 数据源只能被创建一次
        dataSource = new ComboPooledDataSource("XXX");
    }

    /**
     * 返回一个数据源的connection对象
     * 
     * @return
     * @throws SQLException
     */

    public static java.sql.Connection getConnection() throws SQLException {// 这里要转为这种类型
        return dataSource.getConnection();
    }

    /**
     * 释放连接
     * 
     * @param connection
     */
    public static void releaseConnection(java.sql.Connection connection) {
        try {
            if (connection != null) {
                connection.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

c3p0-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
    <named-config name="XXX">
        <property name="user">XXX</property>
        <property name="password">XXX</property>
        <property name="driverClass">org.postgresql.Driver</property>
        <property name="jdbcUrl">
            jdbc:postgresql://localhost:5432/数据库名
        </property>

        <property name="acquireIncrement">5</property>
        <property name="initialPoolSize">10</property>
        <property name="minPoolSize">10</property>
        <property name="maxPoolSize">50</property>

        <property name="checkoutTimeout">0</property>
        <property name="maxStatements">20</property>
        <property name="maxStatementsPerConnection">5</property>

        <!--每60秒检查所有连接池中的空闲连接。Default: 0 -->
        <property name="idleConnectionTestPeriod">60</property>
    </named-config>
</c3p0-config>

因为语句数太多了,所以内存可能会被撑爆。
跳出这样的错误:Error java.lang.OutOfMemoryError: GC overhead limit exceeded
解决方法如下:

Just increase the heap size a little by setting this option in
Run → Run Configurations → Arguments → VM arguments
-Xms3072M -Xmx4096M
Xms - for minimum limit
Xmx - for maximum limit

15份文件可以分3次执行完。
最后再执行error.sql文件。

然后,通过postgresql导出sql文件,数据格式变成这样:

INSERT INTO "public"."tb_imsi_param" VALUES ('1', null, '460018172943802', '8986010512769124302', '1000', '123456', '0', '10', null, '2500', '2501', null, null, '0', '0', null, '30', '2008-06-27', '0', '2013', null, null, '27', 'AYaOTHERS', null, null, '32');
INSERT INTO "public"."tb_imsi_param" VALUES ('2', 'GD005', '460018172966280', '8986010712769234780', '2400', '123456', '0', '7', '集散中心(动)08.1.9-30', '2500', '2501', '57420', '0034', '0', '0', null, '30', '2008-06-27', null, '2013', null, null, '27', 'AYaGD005', null, null, '32');

我们发现,postgresql导出后就没有to_date函数了,再写个程序,只留下数据,最终提交给数据分析人员,用Apache Pig分析。(很简单,就不贴出来了)
样例:

'8', 'GD005', '460018172969895', '8986010712769238395', '2400', '123456', '0', '7', '皇岗集散中心(动)08.01.31-30', '2500', '2501', '57440', '1036', null, null, null, '30', '2008-06-27', null, '2013', null, null, '27', 'AYaGD005', null, null, '32'

以下为本文小结:

关于处理大文件imsi_param2016.sql:
该文件有2个多G,存放的内容是客户oracle数据库中的某张表数据。用Linux的vim等编辑器不能打开,只能less一小部分。
①下载到本地;
②使用notepad++、MySQL Workbench等工具无法打开如此大的文件;
③使用postgresql运行.sql,出现字符集编码不一致导入失败的问题;
④使用“橘子分割”器,把文件拆分成15等份,每份150MB,再通过Java程序对文件进行处理,过滤得到完整的sql。把oracle表转换为postgresql版(因为to_date函数mysql没有);
⑤再分别对15个sql文件,转码成UTF-8;
⑥用程序,把每个文件不完整的sql抽出,并整合成一份error.sql,再人工调整格式;
⑦15分sql文件,逐一运行,确实麻烦,写程序自动运行,一次搞定;
⑧经过如上处理,oracle可转为postgresql且错误率0%。

参考:
http://stackoverflow.com/questions/1393486/error-java-lang-outofmemoryerror-gc-overhead-limit-exceeded


作者: @nanphonfy
Email: nanphonfy (Nfzone) gmail.com 请将(Nfzone)换成@


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
大数据时代下的档案数据挖掘 作者:徐涛 李京林 蓝传锜 来源:《山东工业技术》2018年第05期 摘 要:在信息化高度发展的今天,随着纸质档案数字化转变,正确认识档案信息资源、对 档案信息资源进行合理开发和利用、挖掘用户使用档案行为并进行分析以及关注焦点等 信息,对研究档案的利用具有很大的价值。作为查档用户,通过需求调研发现,单纯的 电子档案信息的调阅已经不能满足如今诸多时间紧任务重的工作环境,如何在尽可能少 的时间内获取尽可能多的有用信息是用户关注的焦点。 关键词:数据挖掘;档案;大数据 DOI:10.16640/j.cnki.37-1222/t.2018.05.116 1 档案数据挖掘的基本认识 1.1 档案数据挖掘的定义与特性 数据挖掘就是从大量的、不完全的、有噪声的、模糊的、随机的数据中,提取 隐含在其中的、人们事先不知道的、但又是潜在的有用信息和知识的过程。对数据化的 档案资源进行数据挖掘,从而找到蕴藏在档案中的价值,获取档案中的知识和规律,这 一过程可以说是从数据到新知识的蜕变。 如,档案人员想要做好档案编研选题,不仅要对用户利用档案数据,包括档案 调卷数量、档案利用次数、复制档案数量、制发档案证明数量等进行深度挖掘,而且还 需要对用户访问记录,包括网页采用的关键字、下载记录、检索词、用户利用网页时间 和频度等信息进行深度挖掘,然后利用分类功能及数据分析,建立档案编研选题的用户 模型,一是按需确定不同类型的编研选题,提供个性化的服务;二是根据档案用户需求 特点,预测其未来趋向,结合社会热点选定档案编研题目,从而使档案编研部门推出用 户满意的编研成果[1]。在档案利用方面,对档案利用登记数据库进行深度挖掘,分别选 取不同方面数据进行建模,可以得出不同档案利用形式的变化趋势,从而对档案利用趋 势进行分析和预测,对利用频率高的档案进行全文数字化,既可以提高档案利用效率, 又可以起到保护档案原件的作用。 因此,档案数据的挖掘是大数据时代的主要特点,档案学的发展历程告诉我们 ,每一次重大的技术变革都必然影响着档案学的发展,如计算机和网络技术的引人,引 起了档案管理理念与实践的变革,改变了文件与档案的处理流程。大数据技术对档案数 据的深度挖掘为档案管理流程由粗放走向精细化提供了可能。 1.2 从数字化档案转变为数据化档案 "数据化"是近两年随着大数据的发展才逐渐被人们从"数字化"概念中逐渐分离 并提出来。最初"数字化"和"数据化"是混为一谈的,数据化的提出不是对数字化的否定 ,而是在对数字世界认识逐步深化的基础上,对数字化理论的拓展与推进。可以说数字 化带来了数据化,但是无法取代数据化。 我国档案界探讨最多的是档案的数字化,在理论和实践方面都取得很多成果。 国家在档案数字化方面出台了《电子文件归档与管理规范》和《纸质档案数字化技术规范》 两个重要的标准规范。在实践中,我国档案数字化主要做了两方面工作:一是档案目录 信息的数字化,即建立档案目录数据库,严格规范档案信息的著录标引,科学选定档案 目录的数据库结构;二是档案全文信息的数字化,即采用扫描录入的方式将档案全文按 照原貌逐页存储为图像文件并为其编制目录索引,或是经OCR(光学字符技术)识别后采 用文本格式存储档案内容,辅之以全文检索数据库[2]。可见,我国在档案数字化过程里 已经无意识地进行了部分档案的数据化,尽管所占的比例很小。 2 数据挖掘技术在档案信息管理中的应用 档案数据挖掘过程中,会用到包括文本信息抽取、文本分类、文本聚类、文本 数据处理等技术进行文本的数据挖掘工作[3]。比如以档案文本数据为基础资源知识库, 根据档案发布的时间信息,分析档案产生的节点趋势以及政府部门针对某一政策的关联 度;对档案类目信息或文本信息进行分词,运用文本分类和文本聚类技术,结合档案数 据的基本属性(时间、所属部门等),对档案进行归类(如按照关键词、档案发布部门 、主题等);采用主题识别技术对档案数据进行抽取,以档案主题为中心,结合档案类 别归属,找出与之关联的档案。基于上述资源,结合多策略的内容抽取,进行文档数据 内容的对比,分析相关政策的影响力、执行力以及变化趋势,从而给政府部门提供相应 的决策资源[4]。同时也可以通过知识管理技术,主要包括信息积累、知识挖掘、知识运 用等,结合信息检索、分析及挖掘技术,将信息进行适当的分类及抽取或形成一组问答 序列,并将这些信息进行提取,形成解决某一问题域的数据集,挖掘出一定的专门知识 ,作为决策的依据,进一步提升档案信息资源的再利用与档案编研工作者的工作效率[5 ]。 3 结语 在信息爆炸的"互联网+"时代,档案工作仍面临三大矛盾:一是档案本质属性与 管理理念的矛盾,智慧时代产生的档案信息以原生电子档案、多媒体档案为主,而档案 部门仍按传统实体档

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值