Problema de análisis de big data

1. Tema y contenido

Problema de análisis de big data

[Descripción del problema]

某搜索公司一天的用户搜索词汇是海量的(百亿数据量),请设计一种求出每天最热top 100 词汇的可行办法。

[requerimientos básicos]

(1) Los datos masivos se generan aleatoriamente y se almacenan en un archivo; los datos se leen del archivo para su procesamiento.
(2) Visualice los resultados de cada procesamiento del archivo de datos.

2. Proceso de pensamiento

(1)生成随机大数据,并且要求大数据存在交集数据,以此保证有热词存在。

(2)顺序读大文件,对于每一行,也就是每个词x,取hash(x)%n,
然后按照该值存到n个小文件中(即为1,2,3,4…..n),这样将MB级别,或者GB级别大文件分块成kb级别,
如果有的文件超过了1M大小,还可以按照类似的方法继续往下分,直到分解得到的小文件的大小都不超过1M;

(3)读入每一个小文件,利用hash_map统计每个文件中出现的词以及相应的频率,
创建动态数据结构node组,存储data(键值)和num(频率),利用最大堆排列,并取出出现频率最大的100个词,
这里注意不一定只有100词,需要统计100之后是否存在和100相同的值,并把100词和相应的频率以结构[key,num]存入文件中,这样又得到n个文件。

(4)把n个文件读入归并成1个文件all.txt, 创建动态数据结构node组,存储data(键值)和num(频率),
利用最大堆排列,取出出现频率最大的100个词,思路到此。

3. Diagrama de flujo del programa y programa anotado

1. Genere archivos de macrodatos

Los datos generados por Python que utilicé aquí se deben a que quería generarlos directamente en el servidor para reducir la carga en la computadora local. Los datos finales generados son 15503190 piezas de datos, que son unos 15 millones, y el espacio es de 81 MB. Aunque este número no llega al nivel de decenas de miles de millones, en teoría, las decenas de miles de millones de datos son la misma idea. La razón por la que el inglés no se usa en chino es porque el uso inicial de caracteres chinos aleatorios, pero la intersección de caracteres chinos es muy pequeña, es difícil tener palabras calientes.

Proceso:
Loop (1.5k) == establecer fuente aleatoria -> seleccionar palabras aleatorias de longitud para fusionar -> guardar archivo
código Python: # que se usa para insertar nuevos datos

1.	def create():  
2.	    filepath = 'data.txt'  
3.	    dataFrom = ['a','b','c','d','e','f','g','h','i','j']  # 随机来源
4.	    for i in range(10000000):  
5.	        if(i%10000 == 0):  
6.	            print(i)  
7.	  
8.	        data = ''  
9.	  
10.	        for j in range(random.randint(2,5)):  
11.	            data += random.choice(dataFrom)  # 产生2到5的长度数据
12.	  
13.	        with open(filepath , 'a' ) as f:  # 存储文件
14.	            f.write(data + '\n')  
15.	            f.close()  

ps: Después de escribir un informe, descubrí que con open no es necesario ejecutar cada ciclo. . . ¡Puede modificarse para ser global!

2. Leer archivos grandes de forma secuencial

Aquí se usa C ++. Para cada línea, es decir, para cada palabra x, tome hash (x)% n, y luego almacene el valor en n archivos pequeños (es decir, 1, 2, 3, 4 ... n) De esta manera, el archivo grande de nivel de MB o nivel de GB se divide en nivel de kb, y el archivo pequeño más grande que obtuve es de 609 kb.

Proceso:
Establecer el tamaño del bloque num -> leer el archivo grande all.txt ->
loop (= verdadero) == calcular el hash de cada línea% num = ubicación del bloque -> almacenar el área del bloque correspondiente

#include <iostream>  
    2.	#include <fstream>  
    3.	#include <string>  
    4.	#include <typeinfo>  
    5.	#include <iomanip>  
    6.	  
    7.	using namespace std;  
    8.	  
    9.	  
    10.	int spit(int num = 500) {  
    11.	  
    12.	    hash<string> str_hash; // 哈希函数  
    13.	  
    14.	    ifstream file;// 大数据来源  
    15.	    file.open("C:\\Users\\lenovo\\Desktop\\大二上作业\\数据结构\\data.txt",
    ios::in);  
    16.	  
    17.	    if (!file.is_open())  
    18.	  
    19.	        return 0;  
    20.	  
    21.	  
    22.	    std::string strLine;  
    23.	  
    24.	    int i = 0;  
    25.	  
    26.	    ofstream *ofile = new ofstream[num+1]; // 预处理存储num个小文件,num可以自定义,这里设置500  
    27.	  
    28.	    for (i = 1; i <= num; i++) { // 目的是open只需要1次,而不是每一次写入都要open,浪费资源  
    29.	        string filename = to_string(i) + ".txt"; // 存储名  
    30.	        ofile[i].open("C:\\Users\\lenovo\\Desktop\\大二上作业\\数据结构\\ton\\" +
    filename);  
    31.	    }  
    32.	  
    33.	    i = 0;  
    34.	  
    35.	    while (getline(file, strLine))// 读入大数据文件每一行  
    36.	    {  
    37.	        i++;  
    38.	  
    39.	        if (strLine.empty()) // 是否为空  
    40.	            continue;  
    41.	  
    42.	        int ton = str_hash(strLine) % num; // 哈希计算分块位置  
    43.	         
    44.	        ofile[ton] << strLine << endl; // 写入一行  
    45.	  
    46.	        if (i % 10000 == 0) {  
    47.	            cout << i << endl; // 每写入10000行输出一次,进度说明  
    48.	        }  
    49.	       
    50.	    }  
    51.	  
    52.	    file.close();  
    53.	    for (i = 1; i <= num; i++) {  
    54.	        ofile[i].close();  
    55.	    }  
    56.	    delete[] ofile;  
    57.	}

3. Leer en cada archivo pequeño

Use hash_map para contar las palabras que aparecen en cada archivo y la frecuencia correspondiente para
crear un grupo de nodos de estructura de datos dinámica, almacenar datos (valor clave) y num (frecuencia), usar la disposición de montón más grande y sacar las 100 palabras con la frecuencia más alta. Nota aquí No necesariamente son solo 100 palabras, es necesario contar si hay el mismo valor que 100 después de 100, y almacenar las 100 palabras y la frecuencia correspondiente en el archivo con la estructura [clave, num], para que se obtengan n archivos.

Este es el lugar central.

Proceso:
loop (500) ==
leer archivos pequeños -> usar hash_map para contar la frecuencia ->
hash_map para atravesar el grupo de árbol de la estructura del nodo ->
usar el montón más grande para ordenar la estructura del árbol ->
generar los 100 datos principales en el archivo

1.	int get100() {  
2.	  
3.	    for (int q = 1; q <= 500; q++) {  
4.	        hash_map<string, int> hm; //建立hash_map 结构 以数据作为key,频率作为value  
5.	        hash_map<string, int> ::iterator it;  
6.	  
7.	        ifstream file; // 建立小文件对象  
8.	        ofstream ofile; // 建立小文件对象  
9.	  
10.	        string filename = to_string(q) + ".txt"; // 文件来向和去向设定  
11.	        file.open("C:\\Users\\lenovo\\Desktop\\大二上作业\\数据结构\\ton\\" + filename, ios::in);  
12.	        ofile.open("C:\\Users\\lenovo\\Desktop\\大二上作业\\数据结构\\100\\" + filename);  
13.	  
14.	        if (!file.is_open())  
15.	            break;  
16.	  
17.	        string strLine;  
18.	        int allNum = 0; // 统计当前小文件的行数,便于创建动态结构node组  
19.	        while (getline(file, strLine)) {  
20.	            if (strLine.empty())  
21.	                continue;  
22.	            hm[strLine] += 1; // hash_map 统计频率  
23.	            allNum++;  
24.	        }  
25.	        cout << "*****" << endl;  
26.	  
27.	        it = hm.begin();  
28.	  
29.	        node* tree = new node[allNum]; // 用来排序  
30.	        int startNum = 0;  
31.	  
32.	        while (it != hm.end()) // 遍历hash_map  
33.	        {  
34.	            tree[startNum].num = it->second; //存储数据  
35.	            tree[startNum].data = it->first;  
36.	            startNum++;  
37.	          //  cout << "pair it_map.key = " << it->first << " pair it_map.string = " << it->second << endl;  
38.	            ++it;  
39.	        }  
40.	  
41.	        Heap_sort(tree, allNum);// 最大堆排列,传入的是node结构  
42.	        cout << "***" << endl;  
43.	  
44.	        int i = 0;  
45.	        while (true) // 输出前一百的数据  
46.	        {  
47.	  
48.	            i++;  
49.	            cout << i << "   " << tree[i].num << "  " << tree[i].data << endl;  
50.	            ofile << tree[i].data <<","<< tree[i].num << endl;  
51.	  
52.	            if (i >= 100 && tree[i].num != tree[i + 1].num) // 保证100之后是否存在和100相同的数据  
53.	                break;  
54.	  
55.	  
56.	  
57.	        }  
58.	        delete[] tree; // 释放空间  
59.	        file.close();  
60.	        ofile.close();  
61.	  
62.	    }  
63.	  
64.	    return 0;  
65.	}  

4. Lea y combine n archivos en un archivo all.txt.

Proceso:
loop (500) == escribe el mismo all.txt -> cuenta el número de filas y regresa.

1.	 int getALl(int &num) {  
2.	  
3.	    ofstream ofile;  
4.	    ofile.open("C:\\Users\\lenovo\\Desktop\\大二上作业\\数据结构\\all.txt"); //来源  
5.	  
6.	    for (int q = 1; q <= 500; q++) {  
7.	        ifstream file;  
8.	  
9.	           
10.	        string filename = to_string(q) + ".txt"; //去向  
11.	        file.open("C:\\Users\\lenovo\\Desktop\\大二上作业\\数据结构\\100\\" + filename, ios::in);  
12.	  
13.	        if (!file.is_open())  
14.	            break;  
15.	  
16.	        string strLine;  
17.	  
18.	        while (getline(file, strLine)) {  
19.	            if (strLine.empty())  
20.	                continue;  
21.	            ofile << strLine << endl;  
22.	            num += 1;  
23.	  
24.	        }  
25.	  
26.	        file.close();  
27.	  
28.	    }  
29.	  
30.	    return 0;  
31.	}  

5. Cree un grupo de nodos de estructura de datos dinámica,

Almacene datos (valor clave) y num (frecuencia), use la permutación de montón máxima y saque las 100 palabras con la frecuencia más alta.
Salida de los 100 datos principales a un archivo

1.	int main() {  
2.	  
3.	    int dataLine;  
4.	    getALl(dataLine);  
5.	  
6.	    cout << dataLine;  
7.	      
8.	    ifstream file;  
9.	    file.open("C:\\Users\\lenovo\\Desktop\\大二上作业\\数据结构\\all.txt", ios::in);  
10.	    ofstream ofile;  
11.	    ofile.open("C:\\Users\\lenovo\\Desktop\\大二上作业\\数据结构\\last.txt");  
12.	   
13.	    node* tree = new node[dataLine];// 动态结构node  
14.	    int startNum = 0;  
15.	  
16.	    string strLine;  
17.	  
18.	    while (getline(file, strLine)) {  
19.	        if (strLine.empty())  
20.	            continue;  
21.	        
22.	        vector<string> v = split(strLine , ","); //分割split;  
23.	        tree[startNum].num = to_int(v[1]);  
24.	        tree[startNum].data = v[0];  
25.	        startNum++;  
26.	  
27.	    }  
28.	  
29.	  
30.	    Heap_sort(tree, dataLine);  
31.	    cout << "***" << endl;  
32.	  
33.	    int i = 0;  
34.	    while (true)  
35.	    {  
36.	        i++;  
37.	        cout << i << "   " << tree[i].num << "  " << tree[i].data << endl;  
38.	        ofile << i << "   " << tree[i].num << "  " << tree[i].data << endl;  
39.	  
40.	        if (i >= 100 && tree[i].num != tree[i + 1].num) // 输出判断前一百  
41.	            break;  
42.	    }  
43.	    delete[] tree;  
44.	    file.close();  
45.	    ofile.close();  
46.	  
47.	  
48.	}  

4. Ejecute el nombre del programa e imprima el valor inicial y el resultado de la operación cuando el programa se esté ejecutando.

1. Genere macrodatos y use Python en el servidor.


Generar archivo:

2. Bloquear 500 archivos

El archivo de origen es de 85 MB y la memoria de bloque ocupa 4 MB


3. Lea en cada archivo pequeño, use hash_map para contar las palabras que aparecen en cada archivo y la frecuencia correspondiente, cree un grupo de nodos de estructura de datos dinámica, almacene los datos (valor clave) y num (frecuencia), use la disposición de montón más grande y elimine Las 100 palabras más frecuentes.

Inserte la descripción de la imagen aquí

4. Finalmente, las primeras cien generaciones

5. Análisis de resultados experimentales, ganancias experimentales y experiencia

1. Esta cuestión de big data es realmente muy importante. Si se trata de un archivo de 10G que requiere 1G de memoria para leer, entonces los requisitos de memoria son muy altos, y la idea clave es dividir y conquistar y bloquear el procesamiento. ! !

2. Al principio, creé el grupo de nodos y no usé el procesamiento de eliminación, lo que provocó que la huella de memoria se disparara a aproximadamente 1G, pero después de la eliminación, ocupa menos de 4 MB, lo que refleja que el código tiene una comprensión muy alta de recursos, y cómo lidiar con la ocupación de recursos es muy importante.

3. La razón por la que hash_map lo usa es también porque su consulta es muy rápida, la complejidad del tiempo es muy baja y su idea también es dividir y conquistar, similar al principio de distribución de cubos.

6. Sugerencias y sugerencias para la mejora del experimento.

El experimento aquí se basa en la idea de dividir y conquistar, pero no tiene que ejecutarse en la máquina local. Cuando los datos alcanzan un cierto nivel, de hecho, la computación distribuida se puede utilizar para dividir los datos en diferentes submáquinas, y las submáquinas transmitirán los datos a la máquina central después del procesamiento. Después de sincronizar los parámetros, continúe dividiéndolos en diferentes submáquinas y luego repita para realizar las estadísticas de los datos.

Y debido a que la cantidad de datos aún no es un gran problema, la distribución de depósitos es 500. Si hay más datos, se pueden dividir más depósitos.

Además, de hecho, se necesitan aproximadamente 290 segundos para completar todo el proceso para 15 millones de procesamiento. Mi dispositivo i5 funciona a 3,7 Ghz y la memoria es de 20 G. Diferentes máquinas pueden tener diferentes tiempos, y el tiempo principal se dedica a leer datos de fila. Pensé si podíamos usar mecanismos de procesamiento de múltiples subprocesos o mapeo de memoria, etc. Más tarde, pensé en el problema de procesar big data con poca memoria. Si el procesamiento de múltiples subprocesos, no tendría sentido. ¡Sería mejor usar el procesamiento distribuido anterior!

Supongo que te gusta

Origin blog.csdn.net/Touale/article/details/112562590
Recomendado
Clasificación