记一次800多万XML文本文件预处理经历

简介:

一.背景

由于某些需求,现需对系统在最近几个月生成的xml文件进行预处理,提取标签内的数据进行分析。这些需要预处理的数据大概有280GB左右880多万,存放在gysl目录下,gysl的下一层按天命名,分为若干个目录,接下来一层目录下又有多个目录,我们所需的xml目录就在这一层。我们现在需要将此目录下面的xml文件使用Python脚本进行处理,并将处理结果按天(与源文件一致)保存到~/temp目录下。

二.操作过程

2.1 Python脚本准备。

#!/usr/bin/python3
# -*- coding:utf-8 -*-
import glob,os,sys, re
from concurrent.futures import ProcessPoolExecutor
import argparse
import random

def find_xs(str, list):
    i = 0
    for i in range(0,len(str)):
        if str[i] in list:
            return i
    return -1

def segement_aux(para, OUT, sep_list, max_length, merge_prob):
    pos = 0
    res_sentence = ""
    sentence_size = 0
    while True:
        #segment one line.
        pos = find_xs(para,sep_list)
        if pos == -1:
            break
        cur_sentence = para[:pos+1].strip()
        cur_sentence_filtering = cur_sentence
        res_sentence = res_sentence + cur_sentence_filtering
        sentence_size = sentence_size + 1
        if sentence_size == 2:
            OUT.write(res_sentence + '\n')
        else:
            rand = random.random() 
            if rand > merge_prob:
                OUT.write(res_sentence + '\n')
                res_sentence = ""
                sentence_size = 0
            else:
                sentence_size = sentence_size + 1
        para = para[pos+1:]
    
def loadXMLfile(inputfile):
    sep_list= ['。', '?', '!']
    targetfolder = "Target"
    max_length = 100000
    merge_prob = 0.6
    basefilename =os.path.basename(inputfile)
    outputfile = targetfolder + '/'+ os.path.splitext(basefilename)[0] + ".tsv"
    textSessionPattern = re.compile(r'<text>(.*?)</text>\s*',  re.I|re.MULTILINE)
    OUT = open(outputfile, 'w',encoding="utf8")
    for line in open(inputfile,encoding="utf8"):
        line = line.strip().rstrip("\r\n")
        alltextsessions = re.findall(textSessionPattern, line)
        for textsession in alltextsessions:
            textsession = re.sub(r'\t', r' ', textsession)
            textsession = re.sub(r'\<[^\<|\>]+\>', r'', textsession)
            textsession = re.sub(r'\{[^\}|\{]+\}', r'', textsession)
            textsession = re.sub(r'\s+',r'',textsession)
            OUT.write(textsession+'\n')
    OUT.close()
    return outputfile
    
def processXMLfilesWithThreads(input):
    with ProcessPoolExecutor() as executor:
        xmlfiles = glob.glob(input + "/*.xml")
        for xmlfile, outputfile in zip( xmlfiles, executor.map( loadXMLfile, xmlfiles) ):
            print("Processed" + outputfile)

if __name__ == '__main__':
    ap = argparse.ArgumentParser()
    ap.add_argument("-i", "--input", required=True, help="the directory of input files")
    args = ap.parse_args()
    processXMLfilesWithThreads(input = args.input)

2.2 Shell脚本准备。

for folder in `find /home/ivandu/gysl -path "*/xml" -print`;do mkdir Target;python3 XMLPreProcess.py --input $folder;mv Target ~/temp/$(echo $folder|awk -F "/" '{print $5}');done

看着有点费劲,改一下:

#!/bin/bash
for folder in `find /home/ivandu/gysl -path "*/xml" -print`;
    do 
        mkdir Target;
        python3 XMLPreProcess.py --input $folder;
        mv Target ~/temp/$(echo $folder|awk -F "/" '{print $5}');
    done

2.3 执行脚本。

此步骤就不展示了,涉及到某些商业机密。在Python脚本所在的目录下,执行Shell脚本就行。

三.遇到问题

3.1 “Argument list too long”。

在执行某目录下的文件移动、复制、删除操作时,发现提示“Argument list too long”,命令执行不成功。这个目录下的文件数量超过30万,操作命令如下:

cp * ~/gysl_test

提示:

-sh: /bin/cp: Argument list too long 

解决方案:

for file in `ls`;do cp $file ~/gysl_test/;done

rm,mv也类似,太忙了也就没继续探讨其他解决方案。

3.2 双for循环执行效率太低。

for folder in `find /home/ivandu/gysl/ -mindepth 2 -maxdepth 2 -print|grep "xml"`;do cd $folder;for file in $(ls);do cp $file ~/gysl_test/;done;done

如果使用这命令来拷贝这些文件的话,那么这一天可能就过去了!这个肯定不妥,必须改进。find也用得不够简洁,后来都进行优化了。

3.3 Python单线程执行效率太低。

Python脚本使用了多线程来进行处理。不过多解释,大家见谅^_^

四.总结

4.1 总体来说今天处理这些数据还是挺给力的,差不多5000秒就完成了。我写了一条命令动态观察了一下。

4.2 正则表达式随时都能用上,要不是处理一下特殊任务和Python多线程,直接一个grep命令写到shell命令或许早就完事了。

4.3 多线程。bash shell中的多线程还不会使用,以后还得加强学习一下。

4.4 就写这么多了,不足之处还望诸位不吝赐教。

相关文章
|
6月前
|
Android开发 开发者
Android自定义View之不得不知道的文件attrs.xml(自定义属性)
本文详细介绍了如何通过自定义 `attrs.xml` 文件实现 Android 自定义 View 的属性配置。以一个包含 TextView 和 ImageView 的 DemoView 为例,讲解了如何使用自定义属性动态改变文字内容和控制图片显示隐藏。同时,通过设置布尔值和点击事件,实现了图片状态的切换功能。代码中展示了如何在构造函数中解析自定义属性,并通过方法 `setSetting0n` 和 `setbackeguang` 实现功能逻辑的优化与封装。此示例帮助开发者更好地理解自定义 View 的开发流程与 attrs.xml 的实际应用。
163 2
Android自定义View之不得不知道的文件attrs.xml(自定义属性)
|
XML 前端开发 Java
讲解SSM的xml文件
本文详细介绍了SSM框架中的xml配置文件,包括springMVC.xml和applicationContext.xml,涉及组件扫描、数据源配置、事务管理、MyBatis集成以及Spring MVC的视图解析器配置。
264 1
|
XML Java 数据格式
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
这篇文章是Spring5框架的实战教程,主要介绍了如何在Spring的IOC容器中通过XML配置方式使用外部属性文件来管理Bean,特别是数据库连接池的配置。文章详细讲解了创建属性文件、引入属性文件到Spring配置、以及如何使用属性占位符来引用属性文件中的值。
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
|
XML Java 数据格式
java创建xml文件内容
java创建xml文件内容
133 0
|
XML Java 数据格式
java解析xml文件内容
java解析xml文件内容
144 0
|
Java Maven
maven项目的pom.xml文件常用标签使用介绍
第四届人文,智慧教育与服务管理国际学术会议(HWESM 2025) 2025 4th International Conference on Humanities, Wisdom Education and Service Management
947 8
|
12月前
|
XML Android开发 数据格式
Eclipse 创建 XML 文件
Eclipse 创建 XML 文件
182 2
|
XML JavaScript Java
java与XML文件的读写
java与XML文件的读写
158 3
|
SQL XML Java
mybatis :sqlmapconfig.xml配置 ++++Mapper XML 文件(sql/insert/delete/update/select)(增删改查)用法
当然,这些仅是MyBatis功能的初步介绍。MyBatis还提供了高级特性,如动态SQL、类型处理器、插件等,可以进一步提供对数据库交互的强大支持和灵活性。希望上述内容对您理解MyBatis的基本操作有所帮助。在实际使用中,您可能还需要根据具体的业务要求调整和优化SQL语句和配置。
240 1
|
XML 存储 缓存
C#使用XML文件的详解及示例
C#使用XML文件的详解及示例
538 0