Вам бонус- начислено 1 монета за дневную активность. Сейчас у вас 1 монета

Инструмент командной строки FST

Лекция



Привет, Вы узнаете о том , что такое Инструмент командной строки FST, Разберем основные их виды и особенности использования. Еще будет много подробных примеров и описаний. Для того чтобы лучше понимать что такое Инструмент командной строки FST , настоятельно рекомендую прочитать все из категории Индексирование большого набора ключей с помощью конечных автоматов.

Инструмент командной строки FST

  • Как его получить
  • Краткое введение
  • Эксперименты
    • Словарь
    • Гутенберг
    • Заголовки Википедии
    • DOI URL
    • Обычное сканирование
    • Производительность запроса

Я создал инструмент командной строки FST как способ легко поиграть с данными и демонстрацию того, как использовать базовую библиотеку. Я не намерен делать это само по себе особенно полезным, но в этом сообщении в блоге он подойдет как способ проведения экспериментов с реальными данными.

В этом разделе я сделаю очень краткий обзор команды, а затем сразу перейду к экспериментам с реальными данными.

Как его получить

Если вы не хотите играть с этим инструментом, вам не обязательно его загружать. А именно, в этом разделе я обычно показываю команды, которые я выполняю, вместе с их результатами, когда это возможно.

В настоящее время единственный способ получить команду - скомпилировать ее из исходного кода. Для этого вам сначала нужно установить Rust и Cargo . (Текущая стабильная версия Rust будет работать. В дистрибутив версии входят как Rust, так и Cargo.)

После установки Rust клонируйте fstрепозиторий и соберите:

$ git clone git://github.com/BurntSushi/fst
$ cd fst
$ cargo build --release --manifest-path ./fst-bin/Cargo.toml

На моей довольно мощной системе компиляция занимает чуть меньше минуты.

После завершения компиляции fstдвоичный файл будет расположен по адресу ./fst-bin/target/release/fst.

Краткое введение

Инструмент fstкомандной строки имеет несколько команд. Некоторые из них служат чисто диагностической роли (например, «Я хочу посмотреть на конкретное состояние в лежащем в основе преобразователе»), тогда как другие более утилитарны. В этой статье мы остановимся на последнем.

Вот команды:

  • dot- Выводит FST в «точечный» формат, который может использоваться GraphViz для визуализации визуального отображения изображения. Я использовал эту утилиту для создания многих изображений в этом сообщении в блоге.
  • fuzzy - Выполните нечеткий запрос на основе расстояния Левенштейна по сравнению с FST.
  • grep - Выполните запрос регулярного выражения для FST.
  • range - Выполните запрос диапазона по FST.
  • set- Создайте упорядоченный набор, представленный FST. Его ввод - простой список строк. По умолчанию он принимает несортированные данные, но может быстрее построить FST, если заданы отсортированные данные и передан --sortedфлаг.
  • map- То же set, что и файл CSV, где первый столбец - это ключ, а второй - целочисленное значение.

setИ mapкоманды имеют решающее значение, поскольку они обеспечивают средства для создания Таблицы FST из простых данных.

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

jan,1
feb,2
mar,3
apr,4
may,5
jun,6
jul,7
aug,8
sep,9
oct,10
nov,11
dec,12

Мы можем создать упорядоченную карту из этих данных с помощью fst mapкоманды:

$ fst map months months.fst

Если наши данные уже были отсортированы, мы могли бы передать --sortedфлаг:

$ fst map --sorted months months.fst

--sortedФлаг указывает fstкоманду , что он может построить FST в потоковом режиме, что очень быстро. Без --sortedфлага он должен сначала отсортировать данные.

Если мы хотим визуализировать базовый преобразователь, это легко, если вы graphvizустановили (что предоставляет dotкоманду, используемую ниже):

$ fst dot months.fst | dot -Tpng > months.png
$ $IMAGE_VIEWER months.png

И вы должны увидеть что-то вроде этого:

Инструмент командной строки FST

Поскольку набор данных невелик, поиск по нему не так интересен, но давайте все же попробуем несколько запросов. Перечислить их все легко с помощью fst rangeкоманды:

$ fst range months.fst
apr
aug
dec
feb
jan
jul
jun
mar
may
nov
oct
sep

Передача --outputsфлага также показывает значения:

$ fst range months.fst
apr,4
aug,8
dec,12
...

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

$ fst range months.fst -s j -e o
jan
jul
jun
mar
may
nov

Или даже нечеткий поиск, ища все месяцы на расстоянии Левенштейна 1с jun:

$ fst fuzzy months.fst jun
jan
jul
jun

У большинства этих команд есть несколько дополнительных опций. Вы можете проверить их, запустив fst CMD --help.

Эксперименты

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

Словарь

С чего еще нам начать? Большинство пользователей систем на базе Unix уже имеют под рукой значительную коллекцию уникальных отсортированных ключей: словарь.

В моей системе он расположен по адресу /usr/share/dict/words(который на самом деле является символической ссылкой /usr/share/dict/american-english). Он содержит 119,095уникальные слова и имеет 1.1 MBразмер.

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

$ fst set --sorted /usr/share/dict/words words.fst

real    0m0.118s
user    0m0.090s
sys     0m0.007s
maximum resident set size: 9.4 MB

Полученный words.fstв настоящее время 324 KB, что 29.4%от исходного размера файла. Для сравнения: одни и те же сжатые данные (LZ77) имеют вид 302 KB( 27.4%), а те же xzсжатые данные (LZMA) - это 232 KB( 21.1%). Настройки по умолчанию использовались со стандартными утилитами командной строки gzipи xz.

С этого момента я представлю эти результаты в более удобной табличной форме. Как только наборы данных станут большими, я перестану использовать, xzпотому что это займет слишком много времени.

Время представлено как время настенных часов, в основном потому, что это удобно, и время быстро станет достаточно большим, чтобы в шуме возникли небольшие отклонения.

Вот первая таблица для набора данных словаря, в котором есть 119,095ключи:

Формат Время Максимальный объем памяти Космос
гладкий - - 1100 КБ
FST 0.12s 9,4 МБ 324 КБ (29,4%)
GZIP 0.15s 1,8 МБ 302 КБ (27,4%)
XZ 0.35s 30,1 МБ 232 КБ (21,1%)

Цель сравнения структуры данных FST с другими алгоритмами сжатия - обеспечить базовое сравнение. Не обязательно быть лучше или быстрее, чем LZ77, LZMA или что-то еще, но это полезные ориентиры. В частности, напомним, что FST на самом деле является структурой данных даже в сжатом состоянии. Общие схемы сжатия, такие как LZ77 или LZMA, плохо подходят для простого произвольного доступа или поиска. Точно так же ни алгоритмы LZ77, ни LZMA не требуют сортировки входных данных до того, как сжатие может работать, что является требованием FST. Следовательно, это не совсем сравнение яблок с яблоками.

Гутенберг

Одним из возможных вариантов использования структуры данных на основе FST является указатель терминов в системе полнотекстового поиска. Действительно, Lucene использует FST именно для этой цели . Следовательно, имеет смысл протестировать FST с помощью словесных ключей.

Я выбрал корпус Гутенберга для этого теста, потому что его легко получить, он свободно доступен и казался достаточно приличным представлением того, что может быть в полнотекстовой базе данных.

После того, как я загрузил весь Gutenberg на свой жесткий диск, я объединил весь простой текст, разделил на пробелы, отсортировал все токены, полученные в результате разделения, и удалил дубликаты. Об этом говорит сайт https://intellect.icu . (Я также убрал знаки препинания и применил к каждому токену строчные буквы ASCII. Токены с более экзотическими буквами Unicode были оставлены как есть.)

Результирующий набор данных содержит 3,539,670уникальные термины. Вот таблица сравнения других форматов сжатия:

Формат Время Максимальный объем памяти Место на диске
гладкий - - 41 МБ
FST 2.04s 21,8 МБ 22 МБ (53,7%)
GZIP 2.50s 1,8 МБ 13 МБ (31,7%)
XZ 14.66s 97,5 МБ 10 МБ (24,0%)

В этом случае мы смогли превзойти скорость gzip, что довольно приятно. К сожалению, FST был только 53.7%размером исходных данных, тогда как в предыдущем примере FST словаря был 29.4%исходных данных. В то время как gzipи по- xzпрежнему выполнять довольно хорошо, их степень сжатия также пострадали. Это может означать, что в данных меньше избыточности.

Мы также должны рассмотреть, как выглядит время для создания FST, если бы токены не были отсортированы заранее.

Если токены из набора данных еще не были отсортированы (т. Е. Мы не можем передать --sortedфлаг fst setкоманде), то это займет немного больше времени. Для набора данных Гутенберга время перескакивает 5.58sи использует 129 MB память.

Стоит сделать паузу, чтобы сказать, что на самом деле происходит, когда --sortedфлаг не передан. В частности, структура данных FST должна быть построена путем вставки ключей в лексикографическом порядке. Это означает, что мы должны сначала отсортировать данные. Проблема с сортировкой заключается в том, что самое простое решение - загрузить все ключи в память, а затем выполнить сортировку. Однако, как мы увидим в будущих наборах данных, это не всегда возможно.

Вместо этого fstкоманда разделит входные данные на несколько частей и отсортирует их по отдельности. После сортировки чанк записывается на диск /tmpкак собственный FST. После того, как все фрагменты отсортированы и преобразованы в FST, мы объединяем все FST в один.

«Пакетная» часть этого процесса способствовала 129 MBиспользованию памяти. В частности, размер пакета по умолчанию - это 100,000ключи, и fstкоманда будет сортировать несколько пакетов параллельно. Уменьшение размера пакета уменьшит объем памяти, необходимый процессу.

Однако это все еще не объясняет общего использования памяти! Фактически, часть «размера резидентного набора», сообщаемая timeкомандой, включает данные, считанные из карт памяти, которые постоянно находятся в памяти. Поскольку все промежуточные FST, созданные из каждого пакета, должны быть полностью прочитаны, чтобы их объединить, из этого следует, что ОС должна была прочитать все данные из каждого FST в память. Примечательно, что эти данные на самом деле не являются частью кучи в нашем процессе. Это означает, что если ваша система нуждается в этом, ОС может фактически заменить неиспользуемую память, которая была первоначально заявлена ​​картой памяти, не обязательно влияя на производительность построения (поскольку после того, как часть FST считана и обработана, она больше не нужна ).

Короче говоря, использование памяти при использовании FST и карт памяти может быть сложно проанализировать.

Заголовки Википедии

Предположим, у вас есть огромная коллекция статей, и вы хотите создать действительно быстрый сервис автозаполнения для заголовков каждой из этих статей. Почему бы не использовать FST для хранения названий? Поиск будет очень быстрым. (Elasticsearch использует FST для своего автозаполнения .)

Для этого варианта использования я не искал дальше Википедии. Он содержит огромную коллекцию статей и служит хорошим репрезентативным примером того, как могут выглядеть реальные данные.

На самом деле загрузить всю Википедию довольно просто . Как только XML каждой статьи оказался на моем диске, я написал быструю программу для извлечения заголовка из каждой статьи в отдельный файл. Затем я отсортировал названия. Всего на диске есть 15,777,626заголовки статей 384 MB.

Давайте посмотрим на сравнительную таблицу для этого набора данных.

Формат Время Максимальный объем памяти Место на диске
гладкий - - 384 МБ
FST 18.31s 34,1 МБ 157 МБ (40,9%)
GZIP 13.08s 1,8 МБ 91 МБ (23,7%)
XZ 140.53s 97,6 МБ 68 МБ (17,7%)

Наша степень сжатия улучшилась по сравнению с набором данных Гутенберга, но мы стали немного медленнее, чем gzipв процессе.

DOI URL

На этом этапе я изо всех сил пытался найти настоящие наборы данных, которые были бы огромными и свободно доступными. Конечно, я мог сгенерировать связку случайных ключей - или попытаться приблизительно представить, как будут выглядеть настоящие данные, - но это было крайне неудовлетворительно.

Затем я наткнулся на набор данных DOI Интернет-архива , содержащий почти 50,000,000URL-адреса журнальных статей. ( DOI - это идентификатор цифрового объекта .)

Набор данных DOI содержит 49,118,091URL-адреса и занимает место 2800 MBна диске. Давайте посмотрим на сравнительную таблицу.

Формат Время Максимальный объем памяти Место на диске
гладкий - - 2800 МБ
FST 27.40s 17,6 МБ 113 МБ (4,0%)
GZIP 40.39s 1,8 МБ 176 МБ (6,3%)
XZ 716.60s 97,6 МБ 66 МБ (2,6%)

Это довольно круто. На этом наборе данных построение FST выполняется быстрее, gzip и степень сжатия у него лучше. Эти данные представляют собой особый случай; однако, поскольку в ключах есть смехотворное количество избыточной структуры. Поскольку это все URL-адреса журнальных статей, существуют длинные последовательности URL-адресов, которые выглядят в основном одинаково, но с немного другим суффиксом. Это почти идеально подходит для FST, поскольку он сжимает префиксы. (Честно говоря, здесь тоже подойдет дерево.)

Обычное сканирование

Я не мог остановиться на наборе данных DOI. 50,000,000ключи большие, и их сжатие всего за 27секунды - хороший результат, но я не рассматриваю его как репрезентативный пример реальных рабочих нагрузок, поэтому было жаль, что самый большой набор данных, который мне пришлось попробовать с FST, также оказался почти лучший сценарий.

Я разместил свой conunudrum на / r / rust , и ta-da, erickt заново научил меня Common Crawl , о котором я совершенно забыл.

Common Crawl огромен . Петабайты огромные. Я честолюбив, но не совсем , что амбициозная. К счастью, хорошие ребята из Common Crawl публикуют свой набор данных в виде ежемесячного дайджеста. Я выполнил сканирование в июле 2015 года, размер которого превышает 145 ТБ.

Это все еще слишком велико. Скачивание всех этих данных и их обработка займет много времени. К счастью, специалисты Common Crawl снова прибегают к помощи: они делают индекс всех файлов «WAT» доступными. Файлы «WAT» содержат метаданные о каждой просканированной странице и не включают фактический необработанный документ. Среди этих метаданных есть URL-адрес, который мне и нужен.

Несмотря на сужение объема, загрузка такого большого объема данных через кабельный модем со скоростью 2 МБ / с не доставит удовольствия. Итак, я создал c4.8xlargeэкземпляр EC2 и начал загружать все URL-адреса из архива сканирования за июль 2015 года с помощью этого сценария оболочки:

#!/bin/bash

set -e

url="https://aws-publicdatasets.s3.amazonaws.com/$1"
dir="$(dirname "$1")"
name="$(basename "$1")"
fpath="$dir/${name}.urls.gz"

mkdir -p "$dir"
if [ ! -r "$fpath" ]; then
  curl -s --retry 5 "$url" \
    | zcat \
    | grep -i 'WARC-TARGET-URI:' \
    | awk '{print $2}' \
    | gzip > "$fpath"
fi

Если сохранить как dl-wat, можно было бы запустить его так:

$ zcat wat.paths.gz | xargs -P32 -n1 dl-wat

И бац, у нас есть 32 параллельных процесса, извлекающих все URL-адреса из архива сканирования. Как только это будет сделано, все, что нам нужно сделать, это получить catфайлы URL (из которых будет по одному для каждого watфайла).

Общее количество URL-адресов, которые я получил, было 7,563,934,593и занимает 612 GB на диске в несжатом виде. После сортировки и дедупликации общее количество URL-адресов есть 1,649,195,774и занимает 134 GBна диске.

Теперь мы можем приступить к созданию нашего FST. Поскольку сортировка URL-адресов займет очень много времени, мы просто позволим fstкоманде сделать это за нас. А именно, в сравнительной таблице ниже показано время, которое потребовалось для первоначального построения из несортированных данных, а также время, которое потребовалось для повторного запуска процесса для отсортированного списка URL-адресов.

Формат Время Максимальный объем памяти Место на диске
гладкий - - 134 ГБ
fst (отсортировано) 82 мин. 56 МБ 27 ГБ (20,1%)
fst (несортированный) 240 минут ? тем же
GZIP 36 минут 1,8 МБ 15 ГБ (11,2%)
XZ - - -

Мои инстинкты относительно того, что URL-адреса DOI являются «идеальным случаем», похоже, подтверждаются этими результатами. А именно, мы вернулись к более реалистичной степени сжатия 20.1%, хотя мы все еще сильно проигрываем gzip.

Нет цифр для, xzпотому что это, вероятно, займет очень много времени.

Еще один момент, о котором стоит упомянуть, - это время, которое потребовалось для создания этого FST. А именно, он содержит в 32 раза больше ключей, чем набор данных DOI, но его выполнение заняло в 182 раза больше времени. На самом деле у меня пока нет полного ответа на этот вопрос. По моим оценкам, кеш, используемый для повторного использования состояний, может снизить производительность, если он заполнен. Другая оценка состоит в том, что, поскольку набор данных DOI имел такую ​​избыточную структуру, ключи можно было обрабатывать быстрее. А именно, большинство ключей, вероятно, привело к компиляции очень небольшого количества состояний. К сожалению, это будет крепкий орешек, потому что FST для набора данных Common Crawl настолько велик, что его трудно проверить с помощью традиционных инструментов.

У меня нет измерения максимальной памяти, используемой несортированным процессом построения, но, как я помню, из наблюдений htopбыло то, что использование разделяемой памяти процессом стало довольно высоким (десятки ГБ). По моим оценкам, это было отражением отображаемой памяти из файлов во время слияния временных FST. Действительно, я мог наблюдать, как его использование разделяемой памяти значительно снижается, когда я запускал такую ​​команду:

$ cat lots of huge files > /dev/null

А именно, читая много больших файлов с помощью cat, я заставил операционную систему выделить часть своего кэша страниц для файлового ввода-вывода, не связанного с fstпроцессом. Поскольку так много его было посвящено fstпроцессу, ОС начала забирать часть из fstпроцесса, и использование общей памяти в fst процессе начало падать.

Действительно, если вы создадите свой собственный большой FST, а затем выполните следующую команду:

$ fst range large.fst | wc -l

и посмотрите, htopпока он работает, вы должны увидеть, как использование совместно используемой и резидентной памяти растет одновременно. Например, в наборе данных DOI использование резидентной памяти постоянно 3 MBбольше, чем использование общей памяти, но оба увеличиваются примерно до 113 MB(размер DOI FST), после чего все ключи были перечислены.

Наконец, давайте взглянем на то, что значит запросить этот огромный FST. Например, возможно, мы хотим найти все URL-адреса Википедии, которые были проиндексированы. Мы можем выбрать поиск по регулярному выражению:

$ fst grep /data/common-crawl/201507/urls.fst 'http://en.wikipedia.org/.*' | wc -l
97054

Когда я впервые запустил эту команду, это заняло 2целые секунды! Что с этим? Что ж, если я снова запустил ту же команду, она завершится примерно через 0.1 секунды. Это большая разница. В самом деле, это потому, что FST не был в памяти, и ОС потребовалось время, чтобы прочитать данные, необходимые для доступа в память. (В частности, это диск с вращающейся ржавчиной, поэтому мы действительно платим за время физического поиска и ввод-вывод файлов. Напомним, что формат FST на диске способствует произвольному доступу.)

Действительно, вывод time -vсообщит нам, что были 164ошибки страниц, которые потребовали, чтобы ОС вышла и выполнила файловый ввод-вывод для устранения. При последующих вызовах это число упало до, 0поскольку эти части файла все еще находились в памяти.

Для быстрого сравнения я скопировал Common Crawl FST на SSD, очистил свой кеш страницы и повторно выполнил тот же grepзапрос. Я подтвердил, что были приблизительно 164ошибки страниц. Общее время выполнения составляло всего несколько 0.16секунд (по сравнению с 2секундами для вращающегося диска с холодным кешем страниц). Повторный запуск снова снижает его до 0.1секунд. Таким образом, использование SSD почти делает кеш страницы неприменимым для быстрых запросов.

Если верить Интернету, мы создали самый большой в мире FST (по количеству ключей). Ура!

Производительность запроса

Серьезным упущением в предыдущих экспериментах являются тесты производительности запросов. Это упущение сделано намеренно, потому что я еще не придумал для него хороший тест. Ключевой частью тестирования производительности запросов является моделирование реальных запросов под нагрузкой. В частности, в идеале он должен включать одновременный запрос нескольких FST и то, что происходит, когда части FST удаляются из кэша страниц операционной системы.

С учетом сказанного, все же стоит понять, на что похожа производительность запросов. Для этого у меня есть микро-тест, который сравнивает членство в двух разных наборах данных между fst::Set, std::collections::HashSetи std::collections::BTreeSet. fst::Set- это заданная структура данных, обсуждаемая в этой статье, представленная FST. HashSetпредставляет собой набор, реализованный с помощью хеш-таблицы. BTreeSetупорядоченный набор, реализованный с помощью btree.

Первый набор данных - это случайная выборка 100,000слов из набора данных Гутенберга. Наш тест ищет случайное слово из набора данных (так что он проверяет только членство в наборе, где ответ всегда «да»).

fst_contains        575 ns/iter
btree_contains      134 ns/iter
hash_fnv_contains    63 ns/iter
hash_sip_contains    84 ns/iter

(Время в наносекундах на операцию. То есть в этом наборе данных членство в наборе для структуры данных FST занимает около 575 наносекунд.)

Названия тестов должны указывать на то, что тестируется. (Разница между hash_fnv_containsи hash_sip_containsзаключается в типе используемой хеш-функции. Первая использует стандартный хэш Fowler-Noll-Vo, а вторая - SipHash, которая криптографически безопасна и медленнее.)

Это демонстрирует, что структуры данных на основе FST действительно имеют худшую производительность поиска, чем классические структуры данных общего назначения. Однако история не так уж и плоха. В этом тесте FST работают 5xмедленнее, чем btrees. Конкретная причина, по которой FST может быть медленнее, заключается в том, что ему нужно выполнять больше работы для декодирования состояний и переходов в базовой машине. Это отличный пример случая, когда алгоритмическая временная сложность не вызывает смеха. В частности, время поиска для таблиц FST является , O(k)где kдлина ключа в то время как время поиска для btrees это O(klogn), где n это количество элементов в наборе. Разница в том, что btree, вероятно, имеет гораздо более быстрый доступ к своим ключам, несмотря на необходимость проводить больше сравнений.

Давайте посмотрим на другой набор данных: 100,000URL-адреса Википедии (из набора данных Common Crawl).

fst_contains        1,169 ns/iter
btree_contains        415 ns/iter
hash_fnv_contains     101 ns/iter
hash_sip_contains     107 ns/iter

Ключи в этом наборе данных немного длиннее (URL-адреса), чем в предыдущем наборе данных (слова из Гутенберга), что объясняет, почему время для всех структур данных увеличилось. Здесь интересно отметить, что поиск структуры данных FST теперь выполняется 2.8xмедленнее, чем поиск btree. Фактически, это именно то, что можно было ожидать с учетом вышеупомянутых гарантий временной сложности. А именно, btree необходимо выполнять lognсравнения, при этом каждое сравнение требует определенных kшагов. С другой стороны, FST нужно выполнить kшаги только один раз. Поскольку этот набор данных имеет гораздо более длинные ключи, стоимость каждогоk шаги увеличились, что снижает производительность поиска по btree по сравнению с FST. Моя гипотеза состоит в том, что по мере роста числа ключей и длины у FST он будет становиться все быстрее и быстрее, чем btree.

Обработка хэш-карты, вероятно, немного сложнее, поскольку время, необходимое для вычисления хеш-кода, равно O(k). Этого достаточно, чтобы получить соответствующее значение. Теоретически хэш-карта может занять O(n)время для поиска в худшем случае, но, по моему опыту, беспокоиться об этом редко (если только вы не реализуете хеш-карту!).

Исследование, описанное в статье про Инструмент командной строки FST, подчеркивает ее значимость в современном мире. Надеюсь, что теперь ты понял что такое Инструмент командной строки FST и для чего все это нужно, а если не понял, или есть замечания, то не стесняйся, пиши или спрашивай в комментариях, с удовольствием отвечу. Для того чтобы глубже понять настоятельно рекомендую изучить всю информацию из категории Индексирование большого набора ключей с помощью конечных автоматов

создано: 2020-08-14
обновлено: 2024-11-14
18



Рейтиг 9 of 10. count vote: 2
Вы довольны ?:


Поделиться:

Найди готовое или заработай

С нашими удобными сервисами без комиссии*

Как это работает? | Узнать цену?

Найти исполнителя
$0 / весь год.
  • У вас есть задание, но нет времени его делать
  • Вы хотите найти профессионала для выплнения задания
  • Возможно примерение функции гаранта на сделку
  • Приорететная поддержка
  • идеально подходит для студентов, у которых нет времени для решения заданий
Готовое решение
$0 / весь год.
  • Вы можите продать(исполнителем) или купить(заказчиком) готовое решение
  • Вам предоставят готовое решение
  • Будет предоставлено в минимальные сроки т.к. задание уже готовое
  • Вы получите базовую гарантию 8 дней
  • Вы можете заработать на материалах
  • подходит как для студентов так и для преподавателей
Я исполнитель
$0 / весь год.
  • Вы профессионал своего дела
  • У вас есть опыт и желание зарабатывать
  • Вы хотите помочь в решении задач или написании работ
  • Возможно примерение функции гаранта на сделку
  • подходит для опытных студентов так и для преподавателей

Комментарии


Оставить комментарий
Если у вас есть какое-либо предложение, идея, благодарность или комментарий, не стесняйтесь писать. Мы очень ценим отзывы и рады услышать ваше мнение.
To reply

Индексирование большого набора ключей с помощью конечных автоматов

Термины: Индексирование большого набора ключей с помощью конечных автоматов