Добавить в корзинуПозвонить
Найти в Дзене
Один Rust не п...Rust

Переработка текста на Rust с ML, Big Data и хранилищем

t.me/oneRustnoqRust Для чего нужна данная статья? : Реализовать максимально быстрый функционал удаления знаков препинания, приведение к нижнему регистру используя: Сбор данных - Источники данных: социальные сети, статьи, отзывы пользователей.
Сохранение данных в распределённое хранилище, например, Hadoop HDFS или Amazon S3.
Предобработка текста - Удаление стоп-слов.
Лемматизация и стемминг.
Токенизация и разбиение на графемы или слова.
Определение языка текста.
Обработка больших данных - Использование фреймворков, таких как Apache Spark, для распределённой обработки текста.
Интеграция с базами данных (например, BigQuery, Cassandra или ClickHouse) для хранения метаданных.
Модель машинного обучения - Создание модели тональности (например, на основе BERT или GPT).
Обучение модели с использованием фреймворков, таких как TensorFlow или PyTorch.
Применение модели к обработанным данным.
Хранилище данных - Сохранение результатов анализа в хранилище данных для дальнейшего использования (нап
Оглавление
ML на RUST без заморочек

t.me/oneRustnoqRust

Для чего нужна данная статья? :

Реализовать максимально быстрый функционал удаления знаков препинания, приведение к нижнему регистру используя:

Сбор данных - Источники данных: социальные сети, статьи, отзывы пользователей.
Сохранение данных в распределённое хранилище, например,
Hadoop HDFS или Amazon S3.

Предобработка текста - Удаление стоп-слов.
Лемматизация и стемминг.
Токенизация и разбиение на графемы или слова.
Определение языка текста.

Обработка больших данных - Использование фреймворков, таких как Apache Spark, для распределённой обработки текста.
Интеграция с базами данных (например,
BigQuery, Cassandra или ClickHouse) для хранения метаданных.

Модель машинного обучения - Создание модели тональности (например, на основе BERT или GPT).
Обучение модели с использованием фреймворков, таких как TensorFlow или PyTorch.
Применение модели к обработанным данным.

Хранилище данных - Сохранение результатов анализа в хранилище данных для дальнейшего использования (например, аналитики, визуализации).

Зачем Вам это уметь? :

Rust предоставляет два основных типа строк: String (изменяемый) и &str (неизменяемая строковая ссылка). Методы работы с ними включают:

Создание строк:

let s1 = String::from("Привет");

let s2 = "Мир".to_string();

Конкатенация строк:

let s = format!("{} {}", "Привет", "Мир");

let s2 = s1 + &s2;

Изменение строк:

let mut s = String::from("Hello");

s.push('!');

s.push_str(" World");

Проверка и поиск:

let contains = "Hello World".contains("World");

let starts = "Hello".starts_with("He");

let ends = "World".ends_with("ld");

Доступ к подстрокам (через срезы &str):

let substring = &s[0..5];

Индексация в строках Rust работает только по байтам, а не символам, так как строки в Rust — это UTF-8. Для работы с символами см. chars().

Rust предоставляет способы работы с символами (char):

Итерация по символам:

for c in "Привет".chars() {

println!("{}", c);

}

Кодовые точки Unicode:

for b in "Привет".bytes() {

println!("{}", b);

}

Фильтрация символов:

let filtered: String = "123abc".chars().filter(|c| c.is_alphabetic()).collect();

Rust не включает регулярные выражения в стандартную библиотеку, но предоставляет популярную библиотеку regex:

use regex::Regex;

let re = Regex::new(r"\d{2}-\d{2}-\d{4}").unwrap();

let text = "Дата: 23-01-2025";

if let Some(mat) = re.find(text) {

println!("Найдено совпадение: {}", mat.as_str());

}

Работа с разделителями

Разбиение строки:

let parts: Vec<&str> = "один,два,три".split(',').collect();

Объединение строк:

let joined = vec!["один", "два", "три"].join(", ");

Трансформация строк

Изменение регистра:

let upper = "hello".to_uppercase();

let lower = "HELLO".to_lowercase();

Тримминг пробелов:

let trimmed = " hello ".trim();

Если необходимо обработать строку как последовательность символов:

Сортировка:

let mut chars: Vec<char> = "rust".chars().collect();

chars.sort();

let sorted: String = chars.into_iter().collect();

Переворачивание строки:

let reversed: String = "rust".chars().rev().collect();

Сравнение строк

Побайтовое сравнение:

let eq = "rust" == "Rust"; // false

Игнорирование регистра (через to_lowercase):

let eq_ignore_case = "rust".to_lowercase() == "RUST".to_lowercase();

Парсинг и форматирование

Парсинг строк в числа:

let num: i32 = "42".parse().unwrap();

Форматирование:

let formatted = format!("{} + {} = {}", 2, 2, 4);

Библиотеки для расширенной обработки текста

unicode-segmentation — для работы с графемами (логическими символами):

use unicode_segmentation::UnicodeSegmentation;

let text = "Привет, мир!";

let words: Vec<&str> = text.unicode_words().collect();

println!("{:?}", words);

inflector — для преобразования регистра, работы с множественным числом и т.д.

Rust поддерживает многопоточную обработку, что может быть полезно для обработки больших текстов:

use rayon::prelude::*;

let words: Vec<&str> = "один два три четыре".split_whitespace().collect();

let uppercased: Vec<String> = words.par_iter().map(|w| w.to_uppercase()).collect();

Обработка больших текстов или файлов

Чтение файла в строку:

use std::fs;

let content = fs::read_to_string("file.txt").unwrap();

Построчная обработка:

use std::io::{self, BufRead};

use std::fs::File;

let file = File::open("file.txt").unwrap();

for line in io::BufReader::new(file).lines() {

println!("{}", line.unwrap());

}

Использование типа Cow для оптимизации работы с неизменяемыми и изменяемыми строками:

use std::borrow::Cow;

fn modify(input: &str) -> Cow<str> {

if input.contains("hello") {

Cow::Owned(input.replace("hello", "hi"))

} else {

Cow::Borrowed(input)

}

}

Реализация переработки текста с использованием ML, Big Data и хранилищ

Следующие библиотеки могут понадобиться:

  • tokio для асинхронной обработки.
  • polars для работы с данными (аналог Pandas в Rust).
  • reqwest для загрузки данных из веб-источников.
  • tch-rs (обёртка PyTorch) для работы с моделями машинного обучения.
  • datafusion для SQL-запросов к данным.
  • rusoto_s3 для работы с Amazon S3.

use polars::prelude::*;

use reqwest::Client;

use tch::{CModule, Device, Tensor};

use rust_tokenizers::{tokenizer::*, vocab::*, BertTokenizer};

use rayon::prelude::*;

use rdkafka::{config::ClientConfig, consumer::{Consumer, StreamConsumer}, producer::{FutureProducer, FutureRecord}};

use std::time::Duration;

#[tokio::main]

async fn main() -> Result<(), Box<dyn std::error::Error>> {

// 1. Настройка Kafka Consumer для получения потоковых данных

let consumer: StreamConsumer = ClientConfig::new()

.set("bootstrap.servers", "localhost:9092")

.set("group.id", "text-processing-group")

.set("enable.partition.eof", "false")

.create()?;

consumer.subscribe(&["text-input-topic"])?;

// 2. Настройка Kafka Producer для отправки обработанных данных

let producer: FutureProducer = ClientConfig::new()

.set("bootstrap.servers", "localhost:9092")

.create()?;

// 3. Загрузка модели для анализа тональности

let model = CModule::load("models/sentiment_model.pt")?;

let device = Device::cuda_if_available();

// 4. Настройка токенизатора (например, BERT)

let vocab = BertVocab::from_file("models/vocab.txt")?;

let tokenizer = BertTokenizer::from_existing_vocab(vocab, true, true);

// 5. Обработка входящих сообщений из Kafka

println!("Waiting for messages from Kafka...");

loop {

match consumer.recv().await {

Ok(message) => {

if let Some(payload) = message.payload_view::<str>().unwrap_or(None) {

// Параллельная обработка сообщений

let results: Vec<_> = payload

.lines()

.par_iter()

.map(|line| {

// Предобработка текста через токенизатор

let tokens = tokenizer.tokenize(line);

let input_tensor = tokens_to_tensor(&tokens, device);

// Анализ тональности через модель

let output = model.forward_ts(&[input_tensor]).unwrap();

let sentiment = output.softmax(-1, tch::Kind::Float).argmax(0, true);

(line.to_string(), sentiment.int64_value(&[]))

})

.collect();

// Формирование результирующего DataFrame

let df = DataFrame::new(vec![

Series::new("text", results.iter().map(|(text, _)| text.clone()).collect::<Vec<_>>()),

Series::new("sentiment", results.iter().map(|(_, sentiment)| *sentiment).collect::<Vec<_>>()),

])?;

println!("Processed DataFrame: {:?}", df);

// Отправка результатов обратно в Kafka

for (text, sentiment) in results {

let record = serde_json::json!({

"text": text,

"sentiment": sentiment

});

producer.send(

FutureRecord::to("text-output-topic")

.key("key")

.payload(&record.to_string()),

Duration::from_secs(0),

).await?;

}

}

consumer.commit_message(&message, rdkafka::consumer::CommitMode::Async)?;

}

Err(e) => eprintln!("Kafka error: {}", e),

}

}

}

// Функция преобразования токенов в тензор

def tokens_to_tensor(tokens: &[String], device: Device) -> Tensor {

let token_ids: Vec<i64> = tokens.iter().map(|t| t.parse::<i64>().unwrap_or(0)).collect();

Tensor::of_slice(&token_ids).to(device)

}