Python之海量数据乱序,生成乱序数据,有序变乱序

一、前言

在做数据库作业时遇到的问题。
作业要求:
• 实现一个基于嵌套循环策略的两表连接算法
在这里插入图片描述
» 数据生成器下载:https://download.csdn.net/download/vpqtxzmzezeqjj9977/12078256

当前难点在于生成的数据时顺序的,我们需要将其数据乱序化。

数据生成过程:https://blog.csdn.net/vpqtxzmzezeqjj9977/article/details/103826925
做这个作业的时候,我切实感受到了大量数据和少量数据的不同。收到时间和内存条件的制约,我们无法将所有数据放到内存中,或者说即使放进去速度也不符合要求的时候,就迫使我们想别的办法。

二、思路

1、少量数据乱序是有函数的,在Ubuntu中有“shuffle”,python中导入random模块之后,对列表list乱序的操作为:random.shuffle(list),在电脑上测试的时候,每次处理200w行数据的乱序的时候还是比较合适的,再大就变慢很多了。
另外我们也可以利用集合set()无序的特点,将列表转化为set()再转化回列表,但这样效果不好结果也得不到保证,因此不推荐使用。
2、大量数据乱序的时候,我们可以用“分而治之”的思路,将数据顺序截取分解存储在100w/个的文件里。
3、使用os模块将文件名存储在列表中,对这个文件名列表进行乱序。
4、按照文件名列表打乱后的顺序,每两个文件拼接存储到一个列表中,组成一个200w的列表,对这个列表乱序,然后平分写回文件,依此类推。

三、优点

1、利用系统函数shuffle,以及分治思想,节约了大量的时间和空间。
2、这样循环一遍之后,每个文件中都含有200w的1/2,重复步骤3、4。理想状态下,下次循环完每个文件中将存有400w的1/4,再下一次将含有800w的1/8,指数增长,从而较快达到乱序的目的。
3、在尽量不影响速度的前提下,将文件存储的尽可能大,可以减少开闭文件耗费的时间。

四、完整代码

import random
import os
import time


# 将大文件切分成多个小文件
def split_files(Filepath, Maxline):
    print('正在进行文件切分。。。')
    # f = open(Filepath + 'orders.tbl', 'r')  # 打开文件
    f = open(Filepath + 'lineitem.tbl', 'r')  # 打开文件
    i = 0  # 设置计数器
    k = 0  # 文件名
    while i < Maxline:  # 这里Maxline表示文件行数
        with open(str(k) + '.txt', 'w') as f1:
            for j in range(0, 2000000):  # 这里设置每个子文件的行数为200W
                if i < Maxline:  # 这里判断是否已结束,否则最后可能报错
                    f1.writelines(f.readline())
                    i = i + 1
                else:
                    break
        k = k + 1
    print('文件切分完成!')
    return k    # 返回文件个数

# 将多个小文件合并为一个大文件
def merge_files(filedir):
    print('正在进行文件合并。。。')
    # 获取目标文件夹的路径
    # filedir = 'D:/test/'
    # 获取当前文件夹中的文件名称列表
    filenames = os.listdir(filedir)
    # 打开当前目录下的orders.tbl文件,如果没有则创建
    # f = open('orders.tbl', 'w')
    f = open('lineitem.tbl', 'w')

    # 先遍历文件名
    for filename in filenames:
        filepath = filedir + '/' + filename
        # 遍历单个文件,读取行数
        for line in open(filepath):
            f.writelines(line)
        f.write('\n')
    # 关闭文件
    f.close()
    print('文件合并完成!')

# 将列表切割成一半,因为n是list_file长度的一半
def cut_list(list_file, n):
    list1, list2 = list_file[0:n], list_file[n:]
    return [list1, list2]


# 文件之间乱序,然后切割
def exchange_ips(Filepath):
    print('正在进行文件乱序。。。')
    pathDir = os.listdir(Filepath)
    random.shuffle(pathDir)
    file_index, l = 0, len(pathDir)
    # 按照此时顺序,文件之间两两交换
    while (file_index + 1 < l):
        filepath1 = Filepath + pathDir[file_index]
        filepath2 = Filepath + pathDir[file_index + 1]
        list_file1, list_file2 = [], []
        f1 = open(filepath1, "r+")
        for line in f1:
            list_file1.append(line)
        f2 = open(filepath2, "r+")
        for line in f2:
            list_file2.append(line)
        # 利用集合快速拼接,同时初步乱序,还有去重的效果
        list_file = list(set(list_file1).union(set(list_file2)))
        half_size = int((len(list_file1) + len(list_file2)) / 2)
        random.shuffle(list_file)
        list_file1, list_file2 = cut_list(list_file, half_size)
        f1.seek(0)
        f1.truncate()  # 清空文件
        f2.seek(0)
        f2.truncate()  # 清空文件
        for item in list_file1:
            f1.write(item)
        for item in list_file2:
            f2.write(item)
        f1.close()
        f2.close()
        file_index += 1
        print(pathDir[file_index - 1] + " and " + pathDir[file_index] + " exchange ok~")
    print('文件乱序完成!')


if __name__ == '__main__':
    Filepath = "D:/test/"
    # 行数:orders行数7500000  lineitem行数29999795
    Maxline = 29999795
    # 将大文件切分成多个小文件
    a = split_files(Filepath, Maxline)
    # 进行a次乱序,a为文件个数
    while (a > 0):
        a = a - 1
        exchange_ips(Filepath)

    merge_files(Filepath)   # 合并

发布了51 篇原创文章 · 获赞 44 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/vpqtxzmzezeqjj9977/article/details/103836176