Skip to content
Merged

Dev #10

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 149 additions & 0 deletions arrow-demo.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/**
* Демонстрация интеграции Apache Arrow с TinyFrameJS
* Этот скрипт показывает, как Apache Arrow используется в TinyFrameJS
* для оптимизации хранения данных
*/

// Импортируем Apache Arrow
const Arrow = require('apache-arrow');

// Создаем простую функцию для создания Arrow вектора
function createArrowVector(data) {
// Определяем тип данных на основе первого элемента
const firstItem = data.find((x) => x !== null && x !== undefined);
const type = typeof firstItem;

if (type === 'string') {
return Arrow.vectorFromArray(data);
} else if (type === 'number') {
return Arrow.vectorFromArray(data, new Arrow.Float64());
} else if (type === 'boolean') {
return Arrow.vectorFromArray(data, new Arrow.Bool());
} else {
return Arrow.vectorFromArray(data.map((x) => String(x)));
}
}

// Создаем простую обертку для Arrow вектора
class ArrowVector {
constructor(vector) {
this._vector = vector;
this.isArrow = true;
}

get(index) {
return this._vector.get(index);
}

toArray() {
return this._vector.toArray();
}

get length() {
return this._vector.length;
}
}

// Создаем простую обертку для TypedArray
class TypedArrayVector {
constructor(array) {
this._array = array;
this.isTypedArray = true;
}

get(index) {
return this._array[index];
}

toArray() {
return Array.from(this._array);
}

get length() {
return this._array.length;
}
}

// Создаем простую фабрику для создания векторов
const VectorFactory = {
from(data, options = {}) {
// Проверяем, нужно ли использовать Arrow
const useArrow =
options.preferArrow ||
options.alwaysArrow ||
typeof data[0] === 'string' ||
data.length > 1000000;

if (useArrow) {
try {
// Пробуем создать Arrow вектор
const arrowVector = createArrowVector(data);
return new ArrowVector(arrowVector);
} catch (error) {
console.error('Error creating Arrow vector:', error);
}
}

// Если не удалось создать Arrow вектор или не нужно его использовать,
// создаем TypedArray вектор для числовых данных
if (data.every((x) => typeof x === 'number')) {
return new TypedArrayVector(Float64Array.from(data));
}

// В остальных случаях возвращаем обычный массив
return {
_array: Array.from(data),
get: (index) => data[index],
toArray: () => Array.from(data),
length: data.length,
};
},
};

// Демонстрация использования Arrow для разных типов данных
console.log('=== Демонстрация Apache Arrow в TinyFrameJS ===');

// 1. Строковые данные - должны использовать Arrow
console.log('\n1. Строковые данные:');
const stringData = ['apple', 'banana', 'cherry', 'date', 'elderberry'];
const stringVector = VectorFactory.from(stringData);
console.log('Тип вектора:', stringVector.constructor.name);
console.log('Использует Arrow:', !!stringVector.isArrow);
console.log('Данные:', stringVector.toArray());

// 2. Числовые данные - должны использовать TypedArray
console.log('\n2. Числовые данные:');
const numericData = [1, 2, 3, 4, 5];
const numericVector = VectorFactory.from(numericData);
console.log('Тип вектора:', numericVector.constructor.name);
console.log('Использует TypedArray:', !!numericVector.isTypedArray);
console.log('Данные:', numericVector.toArray());

// 3. Принудительное использование Arrow для числовых данных
console.log('\n3. Числовые данные с preferArrow:');
const preferArrowVector = VectorFactory.from(numericData, {
preferArrow: true,
});
console.log('Тип вектора:', preferArrowVector.constructor.name);
console.log('Использует Arrow:', !!preferArrowVector.isArrow);
console.log('Данные:', preferArrowVector.toArray());

// 4. Данные с null значениями
console.log('\n4. Данные с null значениями:');
const nullData = ['apple', null, 'cherry', undefined, 'elderberry'];
const nullVector = VectorFactory.from(nullData);
console.log('Тип вектора:', nullVector.constructor.name);
console.log('Использует Arrow:', !!nullVector.isArrow);
console.log('Данные:', nullVector.toArray());

// 5. Большой массив данных
console.log('\n5. Большой массив данных:');
const largeData = Array.from({ length: 1000 }, (_, i) => i);
const largeVector = VectorFactory.from(largeData, { preferArrow: true });
console.log('Тип вектора:', largeVector.constructor.name);
console.log('Использует Arrow:', !!largeVector.isArrow);
console.log('Длина:', largeVector.length);
console.log('Первые 5 элементов:', largeVector.toArray().slice(0, 5));
console.log('Последние 5 элементов:', largeVector.toArray().slice(-5));

console.log('\n=== Демонстрация завершена ===');
77 changes: 77 additions & 0 deletions arrow-test.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/**
* Simple CommonJS script to test Apache Arrow integration
* Using .cjs extension to force CommonJS mode
*/

// Import Apache Arrow
console.log('Attempting to load Apache Arrow...');
let Arrow;
try {
Arrow = require('apache-arrow');
console.log('Apache Arrow loaded successfully');
console.log(
'Arrow exports:',
Object.keys(Arrow).slice(0, 10),
'... and more',
);

// Try to create a vector
if (Arrow.vectorFromArray) {
console.log('\nCreating vector from array...');
const vector = Arrow.vectorFromArray(['test', 'data']);
console.log('Vector created successfully');
console.log('Vector type:', vector.constructor.name);
console.log('Vector length:', vector.length);
console.log('Vector data:', vector.toArray());
} else {
console.log('Arrow.vectorFromArray is not available');
}
} catch (e) {
console.error('Error loading Apache Arrow:', e);
}

// Import our VectorFactory
console.log('\nAttempting to load VectorFactory...');
try {
const {
TypedArrayVector,
} = require('./src/core/storage/TypedArrayVector.js');
const { ArrowVector } = require('./src/core/storage/ArrowVector.js');
const { VectorFactory } = require('./src/core/storage/VectorFactory.js');

console.log('VectorFactory loaded successfully');

// Test with string data (should use Arrow)
console.log('\nTesting with string data:');
const stringVector = VectorFactory.from(['apple', 'banana', 'cherry']);
console.log('Vector type:', stringVector.constructor.name);
console.log('Is ArrowVector:', stringVector instanceof ArrowVector);
console.log('Is TypedArrayVector:', stringVector instanceof TypedArrayVector);
console.log('Vector data:', stringVector.toArray());

// Test with numeric data (should use TypedArray)
console.log('\nTesting with numeric data:');
const numericVector = VectorFactory.from([1, 2, 3, 4, 5]);
console.log('Vector type:', numericVector.constructor.name);
console.log('Is ArrowVector:', numericVector instanceof ArrowVector);
console.log(
'Is TypedArrayVector:',
numericVector instanceof TypedArrayVector,
);
console.log('Vector data:', numericVector.toArray());

// Test with preferArrow option (should force Arrow for numeric data)
console.log('\nTesting with preferArrow option:');
const preferArrowVector = VectorFactory.from([1, 2, 3, 4, 5], {
preferArrow: true,
});
console.log('Vector type:', preferArrowVector.constructor.name);
console.log('Is ArrowVector:', preferArrowVector instanceof ArrowVector);
console.log(
'Is TypedArrayVector:',
preferArrowVector instanceof TypedArrayVector,
);
console.log('Vector data:', preferArrowVector.toArray());
} catch (e) {
console.error('Error testing VectorFactory:', e);
}
9 changes: 7 additions & 2 deletions src/core/dataframe/GroupBy.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
// src/core/dataframe/GroupBy.js
import { DataFrame } from './DataFrame.js';
import { Series } from './Series.js';
import { sum as seriesSum } from '../../methods/series/aggregation/sum.js';
import { mean as seriesMean } from '../../methods/series/aggregation/mean.js';

/**
* GroupBy class for DataFrame aggregation operations
*/
export class GroupBy {
/**
* @param {DataFrame} df - Source DataFrame
Expand Down Expand Up @@ -126,7 +131,7 @@ export class GroupBy {
*/
sum(column) {
const agg = {};
agg[column] = (series) => series.sum();
agg[column] = (series) => seriesSum(series);
return this.agg(agg);
}

Expand All @@ -137,7 +142,7 @@ export class GroupBy {
*/
mean(column) {
const agg = {};
agg[column] = (series) => series.mean();
agg[column] = (series) => seriesMean(series);
return this.agg(agg);
}
}
54 changes: 54 additions & 0 deletions src/core/storage/ArrowAdapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* Adapter for Apache Arrow
* This file provides a compatibility layer for Apache Arrow
* to work with TinyFrameJS regardless of Arrow version
*/

// Import Arrow directly using ESM
import * as Arrow from 'apache-arrow';

/**
* Creates an Arrow Vector from a JavaScript array
* @param {Array} array - The source array
* @returns {Arrow.Vector} - An Arrow vector
*/
export function vectorFromArray(array) {
if (!array || !array.length) {
return null;
}

try {
// Determine the data type based on the first non-null element
const firstNonNull = array.find((x) => x !== null && x !== undefined);
const type = typeof firstNonNull;

// Create appropriate Arrow vector based on data type
if (type === 'string') {
return Arrow.vectorFromArray(array);
} else if (type === 'number') {
return Arrow.vectorFromArray(array, new Arrow.Float64());
} else if (type === 'boolean') {
return Arrow.vectorFromArray(array, new Arrow.Bool());
} else if (firstNonNull instanceof Date) {
return Arrow.vectorFromArray(array, new Arrow.DateMillisecond());
} else {
// For complex objects or mixed types, serialize to JSON strings
return Arrow.vectorFromArray(
array.map((item) =>
item !== null && item !== undefined ? JSON.stringify(item) : null,
),
);
}
} catch (error) {
console.error('Error creating Arrow vector:', error);
return null;
}
}

// Проверка доступности Arrow
export function isArrowAvailable() {
return !!Arrow && typeof Arrow.vectorFromArray === 'function';
}

// Экспортируем Arrow для использования в других модулях
export { Arrow };
48 changes: 25 additions & 23 deletions src/core/storage/VectorFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,31 @@ import { ColumnVector } from './ColumnVector.js';
import { shouldUseArrow } from '../strategy/shouldUseArrow.js';
import { SimpleVector } from './SimpleVector.js';

// Статический импорт Arrow вместо динамического
// Для продакшена лучше использовать условный импорт на уровне пакера (import.meta.env)
let vectorFromArray;
// Импортируем адаптер Apache Arrow
import {
vectorFromArray as arrowVectorFromArray,
isArrowAvailable,
Arrow,
} from './ArrowAdapter.js';

// Попытка загрузить Arrow адаптер синхронно
// Переменная для хранения доступности Arrow
let arrowAvailable = false;

// Инициализация интеграции с Apache Arrow
try {
// Для Node.js используем require
const arrowAdapter = require('apache-arrow/adapter');
vectorFromArray = arrowAdapter.vectorFromArray;
} catch (e) {
try {
// Для браузера можем попробовать использовать глобальный объект Arrow
if (
typeof window !== 'undefined' &&
window.Arrow &&
window.Arrow.vectorFromArray
) {
vectorFromArray = window.Arrow.vectorFromArray;
}
} catch (e2) {
console.warn('Apache Arrow adapter not available at startup');
vectorFromArray = null;
// Проверяем доступность Arrow через адаптер
arrowAvailable = isArrowAvailable();

if (arrowAvailable) {
console.log('Apache Arrow integration initialized successfully');
} else {
console.warn(
'Apache Arrow not available or vectorFromArray function not found',
);
}
} catch (e) {
console.warn('Apache Arrow initialization failed:', e.message);
arrowAvailable = false;
}

export const VectorFactory = {
Expand All @@ -49,10 +51,10 @@ export const VectorFactory = {
* ------------------------------------------------- */
const useArrow = opts.preferArrow ?? shouldUseArrow(data, opts);

if (useArrow && vectorFromArray) {
if (useArrow && arrowAvailable) {
try {
// Используем синхронный вызов vectorFromArray
return new ArrowVector(vectorFromArray(data));
// Используем синхронный вызов arrowVectorFromArray из адаптера
return new ArrowVector(arrowVectorFromArray(data));
} catch (error) {
console.warn(
'Error using Arrow adapter, falling back to TypedArray',
Expand Down
Loading
Loading