Anagram Server-это приложение на основе Node.js, которое открывает API на основе REST для проведения поиска, связанных с анаграммой против словаря слов. Его основная особенность - найти известные анаграммы для данного слова.
Кроме того, наборы Anagram (группы слов, которые являются анаграммами друг друга) могут быть запрошены кардинальностью (количество слов в наборе) или длины слова. Также возможно запросить, содержит ли заданный набор слов анаграмм.
Словарь слов, по которому можно добавить анаграммы, может быть добавлено, удалена или полностью очищена через API. При настройке службы только для памяти (т. Е. Изменения не сохраняются в результате перезапуска службы), Anagram Server загружает стандартный набор английских слов при запуске (см. app.js
).
Наконец, ряд статистических данных о загруженном словаре может быть запрошен через API.
Установите node.js, если это необходимо
Установите зависимости NPM
npm install
npm start
По умолчанию приложение обслуживает запросы через порт 3000. Чтобы переопределить это, вы можете обновить сценарий Start в package.json
, чтобы передать альтернативный номер порта в команду узла. Например:
"start": "node src/app.js -p 8080"
Возможно, вам придется явно разрешить входящий трафик в эффективном порте. Например, открыть порт 3000 на Linux до следующей перезагрузки:
sudo iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 3000 -j ACCEPT
Установите Docker, если это необходимо
Создайте изображение Docker
sudo docker build -t anagram-server .
sudo docker run -p 3000:3000 anagram-server
Вы можете предпочесть сопоставить альтернативный порт хоста (например, -p 8080:3000
).
Сервер Anagram поставляется с тестовыми сценариями Ruby.
Обратите внимание, что по умолчанию предварительно загружает слова Anagram Server из dictionary.txt
при запуске.
Тестовые скрипты находятся в test
подпапке исходного пакета и могут работать индивидуально, как SO:
ruby anagram_test.rb
ruby anagram_test_2.rb
Anagram Server может быть протестирован вручную с помощью cURL
или такого инструмента, как почтальон. Например (из командной строки в новом окне терминала хоста приложения):
curl -i "http://localhost:3000/anagrams/shout.json"
Поскольку по умолчанию предварительно загружает слова Anagram Server из dictionary.txt
при запуске, вы можете очистить словарь с помощью следующей команды до тестирования:
curl -i -X DELETE "http://localhost:3000/words.json"
Для удаленного тестирования замените «Localhost» на IP -хост приложения в anagram_client.rb
и в примере команд этого документа.
Также обновите номер порта в anagram_client.rb
и в примере команд, если запуск сервера Anagram с портом, отличным от по умолчанию (3000).
Слово считается действительным, если оно содержит какую -либо комбинацию верхних и строчных букв английского алфавита или дефиса. Допустимое слово не может запустить или заканчивать с дефисом.
Попытки получить или удалить неверные слова приводят к 400 Bad Request
.
Попытки опубликовать неверные слова приводят к 204 No Content
.
Правильное существительное считается любым словом, в котором есть все строчные буквы, за исключением первой буквы (которая должна быть пропущенной) и первой буквы после дефиса (который может быть прописным или строчным).
Некоторые примеры: английский, зулу, Жан-Кристоф
Правильные существительные считаются отличными от их нижних версий. Например, Эбигейл и Эбигейл - два разных слова (и анаграммы друг друга).
Правильные существительные всегда включены в результаты, если только явно не исключаются (см. excludeProperNouns
parm of GET /anagrams/:word.json
).
Для удобства Anagram Server позволяет в некоторых случаях сопоставить правильные существительные с их нижними версиями. Например, при запросе анаграмм:
$ curl -i "http://localhost:3000/anagrams/aaru.json?includeInput=true"
HTTP/1.1 200 OK
Content-Type: application/json
...
{ "anagrams": [
"Aaru",
"aura"]
}
Архитектура сервера Anagram состоит из 4 слоев (от самого низкого уровня до самого высокого):
Адаптер-это класс, который обеспечивает базовые операции, специфичные для магазина, итерационные и CRUD, используемые Anagram Server. В частности, адаптер предоставляет семантику для связи строки ключей с набором значений, добавления и удаления из набора значений на клавишу, запроса для набора с помощью клавиши и итерационных паров ключей/установки.
Адаптер абстрагирует специфику базового механизма хранения от логики обслуживания, чтобы облегчить обмена одной технологией хранения на другую. Значение этой абстракции состоит в том, чтобы обеспечить легкий путь обновления, поскольку появляются более выгодные альтернативы хранения и обеспечить гибкую масштабируемость.
Например, изначально служба может быть развернута как один сервер приложений с адаптером, который завершает экземпляр MySQL на том же сервере. По мере увеличения потребностей масштабируемости, отказа и производительности мы могли бы обмениваться адаптером на тот, который завершает экземпляр REDIS, который сохраняется и повторяет его данные на нескольких серверах. Специфика того, как данные хранятся, кэшируются и/или воспроизведены, прозрачны для службы Anagram.
Anagram Server отправляется с MemoryAdapter ( adapters/MemoryAdapter.js
), которая использует карту JavaScript для хранения и запросов. Этот адаптер имеет ограниченное приложение, поскольку он не обеспечивает пользу от постоянства между перезагрузками серверов, но он служит хорошей основой для тестирования и демонстрации функций сервера Anagram.
Проект определяет интерфейс для реализации адаптеров в adapters/adapter-template.js
. Этот файл может использоваться в качестве шаблона в определении новых адаптеров.
Интерфейс адаптера основан на обещаниях, поскольку API для технологий хранения, как правило, асинхронно. Теоретически это добавляет время отклика, поскольку обещания разрешаются через очередь событий, но этот эффект незначителен в рамках сетевого запроса.
Транзакции
Методы add()
и delete()
адаптера требуют, чтобы базовый хранилище поддерживал транзакции, поскольку их логика включает в себя запрос данных, а затем работа в магазине на основе результатов запроса.
Результаты клонирования
MemoryAdapter get()
и each()
методы возвращают значения карты, массивы непосредственно в AnagramService. Это требует усердия от имени кода AnagramService, чтобы избежать случайной мутации результатов, предоставленных этими методами.
Клонирование результатов в рамках памяти, прежде чем вернуть их, станет мудрым шагом в смягчении будущих ошибок, обеспечении согласованности интерфейса и придаче наименьшего удивления для потребителей, но также включает в себя дополнительные (хотя и вероятно, незначительные) накладные расходы.
AnagramService - это класс, который предоставляет бизнес -логику для сервера Anagram. Требуется экземпляр адаптера, который должен быть передан его конструктору.
Класс Anagramservice поддерживает слова, а анаграмма подсчитывает и реализует методы, которые непосредственно поддерживают API REST.
Этот класс живет в AnagramService.js
.
server.js
Экспортирует одну функцию startServer()
, которая создает сервер REST (через Restify) и создает экземпляры AnagramService.
startServer()
требует экземпляра адаптера, и, необязательно принимает номер порта, с которого для запросов на обслуживание и необязательный путь к текстовому файлу для предварительной пропалы в словаре.
Meat of server.js
- это набор функций ответа сервера, которые анализируют отдельные HTTP -запросы, вызывают соответствующие методы AnagramService и выдают ответы с помощью соответствующих кодов обертывания объектов и HTTP.
app.js
- точка входа для сервера Anagram. Это простой файл, который определяет адаптер для запуска службы, и дополнительный источник предварительной нагрузки данных.
Это единственный файл, который должен измениться при замене одного адаптера на другой.
Текущая версия app.js
запускает Anagramserver с MemoryAdapter и Preloads dictionary.txt
на запуске.
Ниже приведены некоторые идеи для дальнейшей разработки сервера Anagram.
GET /anagrams/:word.json
Верните множество слов, которые являются анаграммами слова, передаваемого в URL.
Если само пройденное слово не является известным словом (т.е., а не в словаре), возвращается пустой массив (даже если известные анаграммы могут быть сформированы из пропущенного слова).
Для удобства слово, прошедшее как строчное, будет соответствовать ее правильной форме существительного.
Пример:
$ curl -i "http://localhost:3000/anagrams/care.json"
HTTP/1.1 200 OK
Content-Type: application/json
...
{ "anagrams": [
"Acer",
"acre",
"crea",
"race"]
}
GET /anagrams/:word.json?limit=<integer>
Верните массив слов, которые являются анаграммами слова, передаваемого в URL, но ограничить количество возвращаемых результатов .
Пример:
$ curl -i "http://localhost:3000/anagrams/care.json?limit=2"
HTTP/1.1 200 OK
Content-Type: application/json
...
{ "anagrams": [
"Acer",
"acre"]
}
GET /anagrams/:word.json?includeInput=true
Верните множество слов, которые являются анаграммами слова, передаваемого в URL, включая само входное слово .
Входное слово обычно не включено в результаты анаграммы, поскольку слово в условном отношении не считается анаграммой самой.
$ curl -i "http://localhost:3000/anagrams/care.json?includeInput=true"
HTTP/1.1 200 OK
Content-Type: application/json
...
{ "anagrams": [
"Acer",
"acre",
"care",
"crea",
"race"]
}
GET /anagrams/:word.json?excludeProperNouns=true
Верните множество слов, которые являются анаграммами слова, передаваемого в URL, пропуская правильные существительные .
Правильные существительные обычно включаются в результаты анаграммы.
$ curl -i "http://localhost:3000/anagrams/care.json?limit=2&excludeProperNouns=true"
HTTP/1.1 200 OK
Content-Type: application/json
...
{ "anagrams": [
"acre",
"crea"]
}
GET /anagrams?cardinalityMin=<integer>&cardinalityMax=<integer>
Верните все наборы анаграммы, которые имеют минимальную и/или максимальную кардинальность (количество анаграмм в наборе).
Либо кардинальность, либо кардинальность, может быть опущен.
Примеры:
$ curl -i "http://localhost:3000/anagrams?cardinalityMin=3&cardinalityMax=4"
HTTP/1.1 200 OK
Content-Type: application/json
...
{
"anagramsByCardinality": {
"cardinalityMin": 3,
"cardinalityMax": 4,
"anagrams": [
["Aaronic", "Nicarao", "ocarina"],
["abater", "artabe", "eartab", "trabea"],
["Abe", "bae", "Bea"],
...
]
}
}
# Return all words that have anagrams
$ curl -i "http://localhost:3000/anagrams?cardinalityMin=2"
HTTP/1.1 200 OK
Content-Type: application/json
...
{
"anagramsByCardinality": {
"cardinalityMin": 2,
"anagrams": [
["A", "a"],
["aal", "ala"],
["aam", "ama"],
...
]
}
}
GET /anagrams?lengthMin=<integer>&lengthMax=<integer>
Верните все наборы анаграммы, которые имеют минимальную и/или максимальную длину слова.
Либо Lengthmin или LengthMax может быть опущен.
Пример:
$ curl -i "http://localhost:3000/anagrams?lengthMin=10&lengthMax=11"
HTTP/1.1 200 OK
Content-Type: application/json
...
{
"anagramsByLength": {
"lengthMin": 10,
"lengthMax": 11,
"anagrams": [
["ablastemic", "masticable"],
["aborticide", "bacterioid"],
["acalyptrate", "Calyptratae"],
...
]
}
}
GET /anagrams?maxCardinality=true
Вернуть все наборы анаграммы с максимальной кардинальностью.
Пример:
$ curl -i "http://localhost:3000/anagrams?maxCardinality=true"
HTTP/1.1 200 OK
Content-Type: application/json
...
{
"maxCardinalityAnagrams": {
"maxCardinality": 11,
"anagrams": [
["angor", "argon", "goran", "grano", "groan", "nagor", "Orang", "orang", "organ", "rogan", "Ronga"]
]
}
}
GET /anagrams?maxLength=true
Верните все наборы анаграммы с максимальной длиной слова.
Пример:
$ curl -i "http://localhost:3000/anagrams?maxLength=true"
HTTP/1.1 200 OK
Content-Type: application/json
...
{
"maxLengthAnagrams": {
"maxLength": 22,
"anagrams": [
["cholecystoduodenostomy", "duodenocholecystostomy"],
["hydropneumopericardium", "pneumohydropericardium"]
]
}
}
GET /anagrams?areAnagrams=<comma-delimited list of words>
Определите, являются ли набор слов анаграммы друг друга.
Все прошедшие слова должны быть известны (то есть в словаре), чтобы это было правдой.
Пример:
$ curl -i "http://localhost:3000/anagrams?areAnagrams=acer,acre,race"
HTTP/1.1 200 OK
Content-Type: application/json
...
{
"anagramAffinity": {
"areAnagrams": true,
"words": ["acer", "acre", "race"]
}
}
GET /anagrams?count=true
Вернуть только количество Анаграммы. Каждый набор анаграмм в словаре добавляет N-1 к этому количеству, где n -количество анаграмм в наборе.
Пример:
$ curl -i "http://localhost:3000/anagrams?count=true"
HTTP/1.1 200 OK
Content-Type: application/json
...
{ "counts": { "anagram": 20043 }}
GET /words?count=true
Возврат количество слов в словаре.
Пример:
$ curl -i "http://localhost:3000/words?count=true"
HTTP/1.1 200 OK
Content-Type: application/json
...
{ "counts": { "word": 235886 }}
GET /words?stats=true
Верните несколько статистических данных о словах в словаре.
Пример:
$ curl -i "http://localhost:3000/words?stats=true"
HTTP/1.1 200 OK
Content-Type: application/json
...
{
"stats": {
"wordCount": 235886,
"anagramCount": 20043,
"minWordLength": 1,
"maxWordLength": 24,
"medianWordLength": 4,
"averageWordLength": 9.569126612007494,
"minCardinality": 2,
"maxCardinality": 11,
"medianCardinality": 2,
"averageCardinality": 2.3111140184470464
}
}
POST /words.json
Берет массив слов и добавляет их в словарь.
Пример:
$ curl -i -X POST -d '{ "words": ["Canadas", "acandas", "Smurfs", "care"] }' "http://localhost:3000/words.json"
HTTP/1.1 201 Created
Content-Type: application/json
...
{
"counts": {
"word": 3,
"anagram": 1
},
"words": ["/anagrams/Canadas", "/anagrams/acandas", "/anagrams/Smurfs"]
}
DELETE /words/:word.json
Удалить одно слово из словаря.
Если само пройденное слово не является известным словом (т.е. не в словаре), возвращается 404
.
Пример:
$ curl -i -X DELETE "http://localhost:3000/words/care.json"
HTTP/1.1 204 No Content
...
DELETE /words/:word.json?includeAnagrams=true
Удалите одно слово и все его анаграммы из словаря.
Если само прошедшее слово не является известным словом (то есть не в словаре), ничего не удалено, а 404
возвращается.
Пример:
$ curl -i -X DELETE "http://localhost:3000/words/acre.json?includeAnagrams=true"
HTTP/1.1 204 No Content
...
DELETE /words.json
Очистить все содержимое из словаря.
Пример:
$ curl -i -X DELETE "http://localhost:3000/words.json"
HTTP/1.1 204 No Content
...