DUMP-2015: «Распределенная обработка миллионов документов...

Preview:

Citation preview

Scala и AkkaСтепан Каменцев

Распределенная обработка миллионов документов на

План

1. Анализ текстовых коллекций2. Коротко об Akka3. Шаблон Distributed Workers4. Примеры реализации

Что мы делаем?

В начале был хаос!

структурируем

тегируем

собираем статистику

реализуем поиск

представляем инструменты для

анализа

Как мы это делаем?

Мотивация перехода на Akka

type Receive = PartialFunction[Any, Unit]

trait Actor {

def receive: Receive = ???

...

}

class TimeActor extends Actor {

def receive = {

case "Который час?" =>

sender ! System.currentTimeMillis()

}

}

object SomeApp extends App {

val system = ActorSystem("someSystem")

val path = "akka.tcp://sys@host:2552/user/time"

val timeActor = system.actorSelection(path)

timeActor ? "Который час?" onSuccess {

case time => println(time)

}

}

Distributed workers

Распределенные рабы

Требования к системе

1. Динамическое добавление рабочих узлов2. Динамическое добавление клиентов3. Отсутствие дополнительных настроек4. Возможность использовать тысячи узлов5. При падении сети, мастера, рабочего

узла данные не должны теряться

object WorkerToMaster { case object RegisterWorker}

object MasterToWorker { case object WorkerRegistered}

class Worker(master: ActorRef) extends Actor {

import context.dispatcher

context.system.scheduler.scheduleOnce(0.seconds, self, RegisterWorker)

def receive = registration

def registration: Receive = { case RegisterWorker => context.setReceiveTimeout(5.seconds) context.become(waitForRegistration) master ! RegisterWorker } }

class Worker(master: ActorRef) extends Actor {

import context.dispatcher

... ...

def waitForRegistration: Receive = { case WorkerRegistered => context.setReceiveTimeout(Duration.Undefined) context.become(idle) case ReceiveTimeout => master ! RegisterWorker } }

class Master extends Actor { private object clients {...} private object workers { val workerToStatus = mutable.Map.empty[ActorRef, WorkerStatus] } def receive = { case RegisterWorker => val worker = sender() worker ! WorkerRegistered if (clients.isTaskAvailable) { worker ! TasksIsReady } workers.workerToStatus(worker) = Idle}}

Ну, граждане алкоголики, хулиганы, тунеядцы... Кто хочет сегодня поработать?

Песчаный карьер - два человека. Я!

class Worker(master: ActorRef) extends Actor { private def taskExecutorPropsFor(task: Task) = Props( task match { case _: MystemTask => classOf[MystemExecutor] case _: NgramTask => classOf[NgramExecutor] // ... }) def idle: Receive = { case task: Task => context.become(working) val taskExecutor = context.actorOf(taskExecutorPropsFor(task)) taskExecutor ! task currentExecutor = Some(taskExecutor)}}

Отказоустойчивость

class Worker(master: ActorRef) extends Actor {

private var currentExecutor: Option[ActorRef] = None private def interrupt() = currentExecutor.foreach { ref => ref ! PoisonPill currentExecutor = None master ! TaskFailed }

override def supervisorStrategy = OneForOneStrategy() { //... case _: Exception => interrupt() context.become(idle) Restart}}

class Master extends Actor { override def preStart() { context.system.eventStream.subscribe( self, classOf[OnDisassociated]) } def receive = { case OnDisassociated(localAddress, remoteAddress, true) => for (cl <- clients.all if cl.path.address == remoteAddress) clients.release(cl) for (wr <- workers.all if wr.path.address == remoteAddress) workers.release(wr) } }

Примеры реализации

Распределенноепостроение словаря

Функции этапа

1. Токенизация и лемматизация2. Выделение устоявшихся словосочетаний3. Статистика (сколько раз, в каких

документах и т.д.)

object DictionaryClient {

case class DictionaryTask( chunkIdx: Int, databaseConfig: DBConfig ) extends Task

case class DictionaryResult( chunkIdx: Int, lemmas: Map[String, Int], dictionaryBits: java.util.BitSet, lemmasCount: Map[Int, Int], lemmasDocCount: Map[Int, Int] )}

Распределенноепостроение пространства

Функции этапа

1. Построение матрицы лемм и документов2. Сингулярное разложение (Singular Vector

Decomposition)3. Проекция документов на пространство

object SVDClient {

case class SVDTask(chunkIdx: Int, databaseConfig: DBConfig) extends Task

case class SVDResult(chunkIdx: Int, // chunk U * S array data: Array[Byte])}

object ProjectClient {

case class ProjectTask(chunkIdx: Int, databaseConfig: DBConfig) extends Task

case object ProjectResult

}

Кластеризация и тегирование

1. Выделение групп (кластеров) документов2. Тегирование документов и кластеров3. Построение графов лемм

object CBCClient {

case class CBCTask(delta: Double, mergeThresh: Double, committeeThresh: Double, residueThresh: Double, databaseConfig: DBConfig) extends Task

case object CBCResult(centroids: Array[Array[Double]], quality: Array[Double]) }

object KeywordsClient {

case class KeywordsTask(chunkIdx: Int, databaseConfig: DBConfig) extends Task

case object KeywordsResult

}

Вопросы?

email: skamentsev@naumen.ruskype: stepan.kamentsev

Recommended