Anagram Serverは、単語の辞書に対してアナグラム関連の検索を実行するためのRESTベースのAPIを公開するNode.jsベースのアプリケーションです。その主な機能は、特定の単語の既知のアナグラムを見つけることです。
さらに、アナグラムセット(互いのアナグラムである単語のグループ)は、カーディナリティ(セットの単語数)または単語の長さで照会できます。特定の一連の単語がアナグラムセットを含むかどうかを照会することもできます。
アナグラムを照会できる単語の辞書は、APIを介して追加、削除、または完全にクリアできます。メモリのみのサービスとして構成されている場合(つまり、サービスの再起動全体で変更されていない変更)、Anagram Serverは、起動時に標準の英語単語セットをプリロードします( app.js
参照)。
最後に、ロードされた辞書に関する多くの統計をAPIを介して照会できます。
必要に応じてnode.jsをインストールします
NPM依存関係をインストールします
npm install
npm start
デフォルトでは、アプリはポート3000を介してリクエストを提供します。これをオーバーライドするには、 package.json
のStart Scriptを更新して、Nodeコマンドに代替ポート番号を渡すことができます。例えば:
"start": "node src/app.js -p 8080"
効果的なポートでの受信トラフィックを明示的に許可する必要がある場合があります。たとえば、次の再起動までLinuxでポート3000を開くには:
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
など)にマッピングすることをお勧めします。
アナグラムサーバーには、Ruby Testスクリプトが出荷されます。
デフォルトでは、Anagram Serverは、起動時にdictionary.txt
の単語をプリロードすることに注意してください。
テストスクリプトは、ソースパッケージのtest
サブフォルダーにあり、そのように個別に実行できます。
ruby anagram_test.rb
ruby anagram_test_2.rb
Anagramサーバーは、 cURL
またはPostmanのようなツールで手動でテストできます。たとえば(アプリホストの新しい端末ウィンドウのコマンドラインから):
curl -i "http://localhost:3000/anagrams/shout.json"
デフォルトでは、アナグラムサーバーは起動時にdictionary.txt
から単語をプリロードするため、テスト前に次のコマンドで辞書をクリアすることができます。
curl -i -X DELETE "http://localhost:3000/words.json"
リモートテストの場合は、「localhost」をanagram_client.rb
およびこのドキュメントのサンプルコマンドでアプリホストIPに置き換えます。
また、デフォルト(3000)以外のポートを使用してAnagramサーバーを実行している場合、 anagram_client.rb
とサンプルコマンドのポート番号を更新します。
単語は、大文字と小文字の英語のアルファベット文字またはハイフンの任意の組み合わせが含まれている場合、有効と見なされます。有効な単語は、ハイフンで開始または終了しない場合があります。
無効な単語を取得または削除しようとすると、 400 Bad Request
が発生します。
無効な単語を投稿しようとすると、 204 No Content
。
固有の名詞は、最初の文字(大文字でなければならない)を除くすべての小文字があり、ハイフェン(大文字または小文字である可能性がある)を除くすべての小文字を持つ単語と見なされます。
いくつかの例は、英語、ズールー、ジャン・クリストフ
固有の名詞は、小文字バージョンとは異なると見なされます。たとえば、アビゲイルとアビゲイルは2つの異なる単語(およびお互いのアナグラム)です。
適切な名詞は、明示的に除外されていない限り、常に結果に含まれます( GET /anagrams/:word.json
excludeProperNouns
parmを参照)。
便利なため、Anagramサーバーでは、場合によっては小文字バージョンに対して適切な名詞を一致させることができます。たとえば、アナグラムを照会する場合:
$ curl -i "http://localhost:3000/anagrams/aaru.json?includeInput=true"
HTTP/1.1 200 OK
Content-Type: application/json
...
{ "anagrams": [
"Aaru",
"aura"]
}
アナグラムサーバーアーキテクチャは、4つのレイヤー(最低レベルから最高まで)で構成されています。
アダプターは、Anagramサーバーが使用する基本的なストア固有のクエリ、反復、およびCRUD操作を提供するクラスです。具体的には、アダプターは、キー文字列を一連の値に関連付け、キーごとの値のセットに追加して削除し、キーによるセットのクエリ、キー/セットペアを繰り返すためのセマンティクスを提供します。
アダプターは、あるストレージテクノロジーを別のストレージテクノロジーに交換するために、サービスロジックから基礎となるストレージメカニズムの詳細を抽象化します。この抽象化の値は、より好ましいストレージの代替品が出現し、柔軟なスケーラビリティオプションを可能にするため、簡単なアップグレードパスを提供することです。
たとえば、サービスは、最初に同じサーバーにMySQLインスタンスをラップするアダプターを備えた単一のアプリサーバーとして展開される場合があります。スケーラビリティ、フェイルオーバー、およびパフォーマンスの必要性が向上するにつれて、アダプターを複数のサーバーで持続し、データを複製するRedisインスタンスをラップするアダプターに交換する場合があります。データの保存方法、キャッシュ、および/または複製の方法の詳細は、アナグラムサービスに対して透明です。
Anagramサーバーには、JavaScriptのマップを使用してデータを保存およびクエリするために、メモリアダプター( adapters/MemoryAdapter.js
)が付属しています。このアダプターは、サーバーの再起動全体で永続性の利点を提供しないため、アプリケーションが制限されていますが、アナグラムサーバー機能をテストおよび披露するための優れた基盤として機能します。
このプロジェクトは、ファイルadapters/adapter-template.js
にアダプターを実装するためのインターフェイスを定義しています。このファイルは、新しいアダプターを定義する際にボイラープレートとして使用できます。
ストレージテクノロジーのAPIは非同期である傾向があるため、アダプターインターフェイスは約束に基づいています。理論的には、これはイベントキューを介して約束が解決されるため、応答時間を追加しますが、この効果はネットワーク要求の範囲内では無視できます。
トランザクション
アダプターのadd()
およびdelete()
メソッドは、ロジックにはデータの照会を照会し、クエリの結果に基づいてストアで操作するため、トランザクションをサポートするために基礎となるストアが必要です。
クローニング結果
MemoryAdapter get()
およびeach()
メソッドは、マップ値アレイをAnagramServiceに直接返します。これには、これらの方法で提供された結果の偶発的な突然変異を回避するために、AnagramServiceコードに代わって勤勉が必要です。
それらを返す前にメモリアダプター内で結果をクローニングすることは、将来のバグを緩和し、インターフェイスの一貫性を確保し、消費者に最小の驚きを与えるための賢明なステップになりますが、追加の(おそらく無視できる)オーバーヘッドも含まれます。
AnagramServiceは、Anagramサーバーにビジネスロジックを提供するクラスです。コンストラクターに渡すアダプターのインスタンスが必要です。
AnagramServiceクラスは、REST APIを直接サポートする方法を維持し、アナグラムをカウントおよび実装します。
このクラスはAnagramService.js
に存在します。
server.js
RESTサーバーを(RESTIFYを介して)作成し、AnagramServiceをインスタンス化する単一の機能startServer()
をエクスポートします。
startServer()
アダプターインスタンスが必要であり、オプションでサービスリクエストへのポート番号と、テキストファイルへのオプションのパスを受け入れて、辞書を事前に配置します。
server.js
の肉は、個々のHTTP要求を解析し、関連するAnagramServiceメソッドを呼び出し、適切なオブジェクトラッピングおよびHTTP応答コードを使用して応答を発行するサーバー応答関数のセットです。
app.js
、Anagramサーバーのエントリポイントです。これは、サービスを実行するアダプターとオプションのデータプリロードソースを指定する簡単なファイルです。
これは、1つのアダプターを別のアダプターに交換するときに変更する必要がある唯一のファイルです。
app.js
の現在のバージョンは、StartupでメモリアダプターとPreloads dictionary.txt
を使用してAnagramServerを実行します。
以下は、アナグラムサーバーをさらに開発するためのアイデアです。
GET /anagrams/:word.json
URLで渡された単語のアナグラムであるJSONの配列を返します。
渡された単語自体が既知の単語ではない場合(つまり、辞書ではなく)、空の配列が返されます(既知のアナグラムを渡された単語から形成できます)。
便利なため、小文字として渡された単語は、その固有名詞と一致します。
例:
$ 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に渡された単語のアナグラムであるJSON配列を返しますが、返される結果の数を制限します。
例:
$ 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で渡された単語のアナグラムであるJSON配列を返します。
単語は従来はそれ自体のアナグラムとは見なされていないため、入力単語は通常、アナグラムの結果には含まれていません。
$ 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で渡された単語のアナグラムであるJSON配列を返し、固有名詞を省略します。
通常、適切な名詞はアナグラムの結果に含まれています。
$ 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>
最小および/または最大のカーディナリティ(セット内のアナグラムの数)を持つすべてのアナグラムセットを返します。
CardinalityMinまたはCardinalityMaxのいずれかが省略される場合があります。
例:
$ 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>
最小および/または最大単語の長さを持つすべてのアナグラムセットを返します。
onedminまたはonedmaxのいずれかが省略される場合があります。
例:
$ 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
Anagramカウントのみを返します。辞書のアナグラムの各セットは、このカウントに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
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
辞書から1つの単語とそのすべてのアナグラムを削除します。
渡された単語自体が既知の単語ではない場合(つまり、辞書ではなく)、削除されず、 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
...