レベル: 中級 Nicholas Chase (ibmquestions@nicholaschase.com), Writer, Freelance
2008年 2月 12日 XML は Ajax データを渡すための自然なフォーマットのように思えます。しかし、DOM (Document Object Model) を使って JavaScript で XML を扱う方法は、Ajax データなどを扱う上では必ずしも最善の方法ではありません。そのため、開発者がもっとオブジェクトらしい感覚で扱える、JSON など他の選択肢が出てきます。一方、E4X (ECMAScript for XML) は、非常に容易なデータ・バインディングと DOM が持つ最高の機能の多くとを併せ持っているため、ブラウザーで XML を簡単に処理することができます。この 2 回シリーズの記事では、E4X と Prototype JavaScript ライブラリーの両方を使って Ajax による単純な読心術アプリケーション (20 の質問ゲーム) を作成する方法を学び、またその過程で新しいオブジェクトについて学びます。第 1 回では、ユーザーが考えているものを判断するシステムの作成方法について説明します。このシステムでは、既存のナレッジ・ベースを分析し、考えているものを判断します。
完成したアプリケーションは http://www.backstopmedia.com/examples/e4x.html で見ることができます。このシリーズの記事では、読者が XML と JavaScript の概念に慣れていることを前提とします。まだスキルを磨く必要がある場合には「参考文献」を参照してください。また、E4X 対応のブラウザー (Firefox 1.5 以上など) も利用できる必要があります。
何を作成するのか
 |
頻繁に使用される頭字語
- Ajax: Asynchronous JavaScript™ and XML
- DOM: Document Object Model
- HTML: Hypertext Markup Language
- JSON: JavaScript Object Notation
- XML: Extensible Markup Language
|
|
この記事では「20 の質問」という簡単なアプリケーションを作成します。これはユーザーが考えているもの (例えば「house cat (飼い猫)」や「breakfast cereal (朝食シリアル)」など) を当てるゲームです。人間が考えていることを解釈するためには非常に高度なアプリケーションが必要だと思われるかもしれません。実際、十分に学習を重ねた高度なニューラル・ネットワークが http://www.20q.net にはあります。この www.20q.net システムは既に 20数年間も学習を継続しており、さまざまなレベルの確かさ (「Yes (ハイ)」、「No (イイエ)」、「Unknown (わからない)」、「Irrelevant (関係ない)」、「Sometimes (ときどき)」、「Probably (おそらく、そう)」、「Doubtful (たぶん、ちがう)」、など) と、(実行されていると考えられる) あらゆる種類の統計解析により、このシステムが持つデータベースを解釈し、そしてあたかもユーザーの心を読むかのような動作をします。
このシリーズの記事のサンプル・アプリケーションはそれほど高度ではなく、単純な二分探索を行うものです。この二分探索のアルゴリズムは、あるセットの中で適切ではない項目を可能な限り数多く排除し続けると、最終的には求めているものに到達する、という理論に基づいて動作するものです。実際、「20 の質問」という名前は、宇宙にあるどんなものも、イエスとノーで答える約 20 種類の異なる質問を使って絞り込むことで、ただ 1 つの項目にまで絞り込むことができる、という理論に由来しています。
第 1 回では自己完結したシステムを作成します。このシステムは固定のナレッジ・ベースを用意するところから開始し、ユーザーに質問することで、そのユーザーが考えているものを判断します。第 2 回ではシステムが新しいアイテムを学習します。もしシステムが答えを当て損なうと、システムは正しい答えが何だったのか、またその答えのアイテムをナレッジ・ベースの他のものからどう区別するのかを質問します。そしてシステムは、そのアイテムをナレッジ・ベースに追加し、また最初から開始します。最後に、この機能を外部のデータベースと統合し、他の人からシステムが学習したことを誰もが利用できるようにします。
アルゴリズム
さて、これらはどれも言うのは簡単ですが、ブラウザーで「20 の質問」を実装するにはどうすればよいのでしょう。人間が次の質問を考える際には、結局のところ直感を使っていますが、コンピューターに次の質問を決めさせるにはどうすればよいのでしょう。
これに対する答えは、実際には非常に単純であるということがわかります。二部探索法 (もっと一般的に言えば分割統治法) は、1 つの質問ごとに、候補となりうる選択肢の約半分を排除します。つまり、例えば 1024 の選択肢から開始したとすると、最初の質問の後では 512 のみになり、2 番目の質問の後では 256 のみになり、3 番目の質問の後では 128 になるといった具合です。選択肢が 1024 の場合、目標に達するまでに 10 個の質問しか必要ありません。実際、20 個の質問によって 1,048,576 の異なる選択肢を区別することができるのです。
実はこのアルゴリズムはそれほど複雑ではなく、次のように動作します。
- ナレッジ・ベースの全アイテムをロードします。
- そのアイテムが「animal (動物) なのか、vegetable (野菜) なのか、あるいは mineral (鉱物) なのか」をユーザーに質問します。
アプリケーションの他の部分では単に「yes (ハイ) か no (イイエ) か」という答えを使いますが、この質問は伝統的な「最初の質問」であり、この質問によって、候補となりうる選択肢の約 2/3 を最初に排除します。
- 質問に対する答えに合わないアイテムをすべて排除します。
- 1 つのアイテムのみになったら、それが正しい答えかどうかをユーザーに質問します。
答えが正しければ、ナレッジ・ベースをリロードし、始めからまた繰り返します。答えが正しくなければ、正しい答えを知るために、どんな質問をすれば正しい答えと誤った答えとを区別できたのかをユーザーに尋ねます。そしてこの情報をナレッジ・ベースに追加します (これは第 2 回で行います)。
- まだ複数のアイテムが残っているうちは、残っているアイテムのうちの最も多くのアイテムに共通する質問となるように質問を決めます。(これが重要な点です。これによって、答えとなりうるアイテムを最も多く排除することができます。)
- その質問をします。
- ステップ 3 に戻ります。
調べてみるとわかるとおり、E4X はこうした種類のアルゴリズムに非常に適しているのです。
注意: 残念なことに、正しい情報をナレッジ・ベースに追加するように人々に強制することはできません。しかし正しい情報を追加しない人達は、実質的に自分たちが追加する情報を発見不能にしているのです。
E4X の紹介
皆さんがプログラムで XML を扱うことを考える場合、最初に頭に浮かぶことは何でしょう。DOM でしょうか。XPath でしょうか。あるいは、最初に頭に浮かぶことは「えい、面倒くさい」という言葉かもしれません。そのとおりです。XML は素晴らしいデータ・ストレージ・フォーマットであり、そして非常に操作が面倒です。しかし、もし XML オブジェクトを容易に作成でき、XML ノードに容易にアクセスしてフィルタリングすることもでき、表示あるいは保存用に容易にデータをシリアライズできるとしたらどうでしょう。そうすれば XML の操作はそれほど苦痛ではなくなるはずです。
そこに E4X が登場します。
E4X はデータ・バインディング風の構造を使用しているため、XML 文書の一部に容易にアクセスできるようになっています。例えば次のスニペットを考えてみてください (リスト 1)。
リスト 1. E4X を使う
<script type="text/javascript;e4x=1">
myquestion = <question>
<display>Is it animal, vegetable, or mineral?</display>
<answerOption>Animal</answerOption>
<answerOption>Vegetable</answerOption>
<answerOption>Mineral</answerOption>
</question>;
alert("The question is '" + myquestion.display + "'");
</script>
|
注意: このスクリプトの型宣言に注意してください。初期の Mozilla での E4X 実装の後方互換機能を一部オフするために、型の最後に「;e4x=1」を追加する必要があります。
まず、宣言対象となる XML が引用符で囲われていないのはタイプミスではありません。実際、引用符で囲わずにコードの中で使えるのです。後でわかりますが、これは便利です。(幸い、ストリングからオブジェクトを作成するオプションもあります。これも後でわかります。) 第 2 に、単純なオブジェクト構文を使うことで表示要素の値を取得できることに注目してください。結果は図 1 のようになります。
図 1. XML からの情報を表示する
実はテキストではないデータの場合も情報を簡単に取得できるのです。リスト 2 を考えてみてください。
リスト 2. 生データを表示する
...
</question>;
alert("The question is \n" + myquestion);
|
ここでは XML 文書全体を参照しているので、実際にその文書全体を取得することができます (図 2)。
図 2. 要素全体を表示する
簡単だと思いませんか。難解なシリアライザーや変換は必要なく、必要なまさにその場所で適切なデータを取得できるのです。
E4X は、これから必要となる 2 つの基本的なクラス XML() と XMLList() を提供しています。XML() は document または element に近いものであり、XMLList() は Nodelist に近いものです。この記事では、この両方のクラスの実際の動作を説明します。
では、アプリケーションを作成しましょう。
ナレッジ・ベースを作成する
最初のステップは実際のナレッジ・ベースを作成することです。そのためには、質問 (question) と、質問が参照するターゲット (target) の両方を含む 1 つの XML 文書を使います (リスト 3)。
リスト 3. ナレッジ・ベースを作成する
kdata =
<knowledgebase>
<questions>
<question id="1">
<display>Is it animal, vegetable, or mineral?</display>
<answerOption>Animal</answerOption>
<answerOption>Vegetable</answerOption>
<answerOption>Mineral</answerOption>
</question>
<question id="2">
<display>Does it bark?</display>
<answerOption>Yes</answerOption>
<answerOption>No</answerOption>
</question>
</questions>
<targets>
<target id="1">
<display>a house cat</display>
<answer questionid="1"><answerValue1>Animal</
answerValue1></answer>
<answer questionid="2"><answerValue2>No</
answerValue2></answer>
</target>
<target id="4">
<display>a dog</display>
<answer questionid="1"><answerValue1>Animal</
answerValue1></answer>
<answer questionid="2"><answerValue2>Yes</
answerValue2></answer>
</target>
<target id="2">
<display>a carrot</display>
<answer questionid="1"><answerValue1>Vegetable</
answerValue1></answer>
</target>
<target id="3">
<display>a ruby</display>
<answer questionid="1"><answerValue1>Mineral</
answerValue1></answer>
</target>
</targets>
</knowledgebase>;
knowledgeBase = new XML(kdata);
|
先に進む前に、この構造を見てください。この構造の中に、このアルゴリズムで最も重要な部分が含まれているのです。まず質問 (questions) があり、その後にターゲット (targets) があります。質問の方は簡単で、それぞれの質問 (question) には、実際に表示される質問 (display) と、その質問に対して考えられる答え (answerOption) が含まれています。最初の質問を除いて、「yes」または「no」のみを使います。この構造によって、候補となりうる答えを後で追加できる柔軟性が得られています。
ターゲット (target) には、ターゲット ID (target id) とターゲットの表示名 (display)、そして各質問に対してシステムが持っている答え (answer) が含まれています。例えば、システムは「a dog (犬)」が「animal (動物)」であり、「a dog (犬)」が「bark (吠える)」ということを知っていますが、一方「a carrot (人参)」について知っていることは「a carrot (人参)」が「vegetable (野菜)」だということだけです。もちろん、それだけ知っていれば十分です。野菜が吠えると思う人はいません。
システムは新しい質問と答えを学習すると、それらの質問と答えを必要に応じて既存のターゲットに追加します。
ヒント: もっと賢明なシステムから開始したい場合には、最新のナレッジ・ベースを http://backstop.nicholaschase.com/knowledgebase.php?getkb=YES からダウンロードすることができます。
質問を表示する
次のステップは、実際に最初の質問をすることです。そのためには、その質問を表示する必要があります。これを容易にするための 1 つの方法としては、カスタマイズ可能な HTML を作成する方法があります (リスト 4)。
リスト 4. 質問用のフォーム
<html>
<head>
<title>E4X mindreader</title>
<script type="text/javascript; e4x=1" src="e4x.js"></script>
<style type="text/css">
.answerLink {color: blue; text-decoration: underline}
</style>
</head>
<body style="background-color:#abdfe7;" onload="ask_question()">
<div id="questionFormDiv"
style="position: absolute;top: 50px;visibility: hidden; width: 100%;">
<span id="displayQuestion"></span><br />
</div>
</body>
</html>
|
この HTML は、テキストを挿入するための span を持つ、オン/オフできる div (オフが初期値) を含む いうものです。これを行うためには特定の XML 要素を選択できる必要があります。
ノードをフィルタリングする
E4X では、フィルターを使ってノードまたはノード群を選択することができます (リスト 5)
リスト 5. フィルターを使う
...
knowledgeBase = new XML(kdata);
var currentQuestion = 1;
//******************************
// BEGIN FUNCTIONS HERE
//******************************
function ask_question(){
var questionElement = knowledgeBase.questions.question.(@id == currentQuestion)
var questionDisplay = questionElement.display;
document.getElementById("displayQuestion").innerHTML = questionDisplay ;
show_form("questionFormDiv");
}
function hide_form(divName){
document.getElementById(divName).style.visibility = "hidden" ;
}
function show_form(divName){
document.getElementById(divName).style.visibility = "visible" ;
}
|
この HTML ページはロードされると answer_question() 関数を呼び出します。そこで、まずこの関数を作成します。最初のステップでは、最初の質問を表す XML を格納する変数、questionElement を作成します (全体を通じてどんな質問に対する作業なのかを知る必要があるため、単純にこの変数をグローバルにします。こうすることは理想的なプログラミング・プラクティスではありませんが、これは本番用アプリケーションを意図したものではありません。)
ask_question() 関数の先頭の構文に注目してください。この構文は XPath の述部に非常に似ており、また XPath の述部と同じように動作します。この場合ではナレッジ・ベースを選択し、次にルート要素の子である questions に移動し、さらに questions 要素のすべての question という子にまで移動します。そしてそこから、フィルタリングの条件を満足しないすべての question 要素 (つまり求める question 以外のすべての要素) を排除します。
その結果、1 つの要素が得られ、その要素の display という子を容易に引き出すことができ、そして標準的な DOM 操作によってそれをページ上に表示することができます (図 3)。
図 3. 質問を表示する
今度は考えられる答えを追加する必要があります。
XMLList を処理する
ユーザーが情報を入力できるページを作成するためには、さまざまな方法があります。この場合は span を使ってリンクをシミュレートします (リスト 6)。
リスト 6. 答え
<span id="displayQuestion"></span><br />
<span class="answerLink"
onclick="answer_question(this)" id="answer1Text"></span>
<span class="answerLink"
onclick="answer_question(this)" id="answer2Text"></span>
<span class="answerLink"
onclick="answer_question(this)" id="answer3Text"></span>
|
これらのリンクは answer_question() 関数を参照するように構成されています (answer_question() 関数の作成方法は、このすぐ後に説明します)。しかしまず、答えの部分にデータを追加する必要があります (リスト 7)。
リスト 7. 答えの部分にデータを追加する
...
document.getElementById("displayQuestion").innerHTML = questionDisplay ;
var answerOptions = new XMLList();
answerOptions = questionElement.answerOption;
var answerCounter = 0;
document.getElementById("answer3Text").innerHTML = "";
for each( var answerText in answerOptions) {
answerCounter++;
document.getElementById("answer"+answerCounter+"Text").innerHTML =
answerText;
}
}
...
|
変数 answerOptions は、DOM の Nodelist に似た XMLList で構成されています。ここでは、answerOptions は現在の questionElement 要素の一部である、すべての answerOption 要素で構成されています。次に、このリストを for each ループの中で使用して各 answerOption 要素を順次参照し、それを適切な span に追加します。(最初の質問の後で 3 番目の span を使うことはないため、最初に 3 番目の span をクリアーします。)
この結果として、各 answerOption 要素へのリンクを含むページが作成されます (図 4)。
図 4. 最初の質問
では、ユーザーがこの質問に答えると何が起きるのでしょう。
質問に答える
ユーザーが質問に答えたら、その答えに基づいてもはや答えになり得ないアイテムをすべてフィルタリングして排除する必要があることを思い出してください。まず、現在考慮の対象となっている一連のターゲットを取得する必要があります (リスト 8)。
リスト 8. 現在のターゲットを取得する
...
var currentQuestion = 1;
var currentTargetSet = knowledgeBase.targets;
//******************************
// BEGIN FUNCTIONS HERE
//******************************
function ask_question(){
...
}
function answer_question(answerSpan){
hide_form("questionFormDiv");
var theAnswer = answerSpan.innerHTML;
var remainingTargets =
currentTargetSet..target.(answer["answerValue"+currentQuestion]==theAnswer);
alert("There are "+remainingTargets.length()+" targets remaining: \n" +
remainingTargets);
}
...
|
このリストの先頭で新しいオブジェクト currentTargetSet を作成していることに注目してください。このオブジェクトは最初は targets 要素全体を保持していますが、answer_question() を実行するところまで来ると、このオブジェクトの内容を絞り込んでいきます。
ユーザーの答えを取得したら (この関数は実際の span を引数として受け取ることを思い出してください)、currentTargetSet をフィルタリングして、新しい XMLList である remainingTargets を作成します。
この式で私が 2 つのピリオドを使っていることに注意してください。XPath が二重スラッシュ (//) 表記を使って子孫を表現するのと同じように、E4X は二重のピリオド (..) を使います。ここではまずルート要素の target という子孫をすべて取得してから、それらをフィルタリングして減らします。
このフィルター部分をよく見てください。大括弧を見て XPath の述部のことを考えたかもしれませんが、ここでは述部の役割をしているわけではなく、answer 変数はハッシュなのです。JavaScript からフォーム要素を参照するための従来の方法と同じように、answer["answerValue1"] という式は answer.answerValue1 と同じことを意味しています。
この方法の利点は、検索対象である要素に対して動的に名前を付けられることです。この場合フィルターは、ユーザーから与えられる答えに一致する値を使って、answer.answerValue1 という子孫を持つ target 要素を探します。
これまでと同じく、フィルタリング・プロセスによって XMLList が作成されるので、リストの長さを取得すれば target がいくつ残っているかを知ることができます。例えば、もしユーザーが「Animal」を選択すると、まだ 2 つのターゲットが残っていることがわかります (図 5)。
図 5. 2 つのターゲットが残っている
まだ 2 つのターゲットが残っているので、その 2 つを区別するために、次に尋ねる質問を考えなければなりません。
次に尋ねる質問を選択する
このアルゴリズムによれば、次の質問は、残っているターゲットの間に最も共通する質問にする必要があるため、ある想定をしなければなりません。本番システムではおそらく、尋ねられる各質問を保存したり、あるいは既に尋ねた質問を確実に排除したりするための別の方法を考えるでしょうが、この例の場合では、先に進むにつれて質問はより具体的になっていくこと、そしてナレッジ・ベースはもっとたくさんのアイテムを含んでいることを想定します。そうする理由は、questionid の値は先に進むにつれて大きくなることを前提にし、既に尋ねた質問を簡単に排除できるようにするためです (リスト 9)。
リスト 9. 既に尋ねた質問を排除する
...
var remainingTargets =
currentTargetSet..target.(answer["answerValue"+currentQuestion] == theAnswer);
alert("There are "+remainingTargets.length()+" targets remaining: \n" +
remainingTargets);
var targetContainer = <targets/>;
currentTargetSet = new XML(targetContainer);
currentTargetSet.targets = remainingTargets;
if (remainingTargets.length() == 1){
// Make a guess
} else {
var remainingAnswers = currentTargetSet..answer.(@questionid > currentQuestion);
mostPopularQuestionCount = 0;
mostPopularQuestionId = 0;
get_most_popular_question(remainingAnswers);
currentQuestion = mostPopularQuestionId;
ask_question();
}
}
var mostPopularQuestionId = 0;
var mostPopularQuestionCount = 0;
function get_most_popular_question(answersToCheck){
var answersToCheckElement = <answersToCheckRoot/>;
var checkElement = new XML(answersToCheckElement);
checkElement.appendChild(answersToCheck);
var firstId = checkElement..answer[0].@questionid;
var thisQuestionCount = checkElement.answer.(@questionid == firstId).length();
if (thisQuestionCount > mostPopularQuestionCount){
mostPopularQuestionCount = thisQuestionCount;
mostPopularQuestionId = firstId;
}
answersToCheck = checkElement..answer.(@questionid != firstId);
if (answersToCheck.length() > 0){
get_most_popular_question(answersToCheck);
} else {
// alert("Most popular question is "+mostPopularQuestionId+",
with "+mostPopularQuestionCount+" answers.")
}
}
...
|
ユーザーの答えに合わないターゲットをすべて排除し、1 つのアイテムのみが残ると、答えを当てる時が来たということです。
一方、もし残っているアイテムが複数ある場合には、まず currentTargetSet を再構成する必要があります (remainingTargets が target 要素の単なるリストであることを思い出してください)。つまり最初のステップは、ルート要素を持つ新しい文書を作成し、その文書にこれらの残っている target 要素を追加することです。
それが終わったら、現在の質問よりも大きな questionid を持つ、残るすべての答えの XMLList を取得することができます。これらの答えの中から、最も共通する質問を選択する必要があります。
そのためには再帰関数 get_most_popular_question() を作成します。この関数は実行されるたびに、見つかる最初の questionid の値を選択し、その質問に対する答えがいくつ現在のセットの中にあるかを判断します。そしてその数がその時点での、質問に対する答えの数として、最大であるかどうかをチェックします。現在のセットの中に他の質問 (questionid の値) がまだ残っていれば、それらの質問に対してこのルーチンを再び実行します。
最後に currentQuestion を、答えの数が最大の、最も共通する質問に設定して戻り、そして再度質問します。
この場合、最初に Animal (動物) を選択すると、残るターゲットが 2 つ (「a house cat (飼い猫)」と「a dog (犬)」) であることがわかります。質問 1を排除すると、最も一般的な質問は id が 2 の、「Does it bark? (それは吠えますか?)」です。
答えを当てる
ユーザーが質問「Does it bark? (それは吠えますか?)」に答えると、ターゲットは 1 つしか残っていません。答えが何であれ、答えを当てなければなりません (リスト 10)。
リスト 10. 答えを当てる
...
var targetContainer = <targets/>;
currentTargetSet = new XML(targetContainer);
currentTargetSet.targets = remainingTargets;
if (remainingTargets.length() == 1){
currentGuessText = currentTargetSet.target.display;
currentGuessId = currentTargetSet.target.@id;
guess();
} else {
var remainingAnswers =
currentTargetSet..answer.(@questionid > currentQuestion);
get_most_popular_question(remainingAnswers);
currentQuestion = mostPopularQuestionId;
ask_question();
}
}
var currentGuessText = "";
var currentGuessId = "";
function guess(){
document.getElementById("guessSpan").innerHTML = currentGuessText;
show_form("guessDiv");
}
...
|
答えを当てる準備ができたということは、currentTargetSet にはその答えしか含まれていないということです。そこで currentGuessText と currentGuessId に対してグローバル変数を作成し、guessDiv を表示します (リスト 11)。
リスト 11. 答えを当てるためのフォーム
<div id="guessDiv" style="position: absolute; top: 50px;visibility: hidden;
width: 100%;">
It's <span id="guessSpan"></span>, right?<br />
<a href="#" onclick="start_over()">YES! You're right!
Let me try again.</a><br />
<a href="#" onclick="get_new_target()">No, sorry!</a><br />
</div>
</body>
</html>
|
すると、もし「Animal (動物)」、「Yes (ハイ)」を選択すると、このアプリケーションは「a dog (犬)」を言い当てるはずです (図 6)。
図 6. 最初の答え
このアプリケーションが言い当てた答えが誤っている場合にどうなるかは第 2 回で説明しますが、アプリケーションが正しい答えを言い当てたときにどうするかをまず調べましょう。
正しい答えを当てる
関数 start_over() は非常に単純です (リスト 12)。
リスト 12. 最初からやり直す
function start_over(){
hide_form("guessDiv");
currentQuestion = 1;
currentTargetSet = knowledgeBase.targets;
ask_question();
}
|
最初からやり直すためには guessDiv の表示を消し、currentQuestion と currentTargetSet の両方をリセットして、ask_question() に戻って最初の質問を再度表示します。
しかし、もし答えが誤っていたらどうなるのでしょう。もしアプリケーションが誤った答えをしたら、正しい答えをアプリケーションに教える必要があります。その方法については第 2 回で説明します。
次のステップ
この記事では、E4X の使い方を学ぶために「20 の質問」というゲームの形式でバブルソート・ルーチンを実装しました。E4X の XML() オブジェクトと XMLList() オブジェクトの両方の作成方法と操作方法を学び、またこれらのオブジェクトの中のデータに、オブジェクト構文を使ってアクセスする方法を学びました。さらに、フィルターを使って、指定されたセットの中のノードを制限する方法も学びました。
しかしまだ、このアプリケーションは非常に単純です。本番のアプリケーションでは、答えの候補の範囲を広げるために「sometimes (ときどき)」あるいは「I don't know (わからない)」などを含めたいと思うかもしれませんが、そうするとアルゴリズムの複雑さも増し、1 つのアイテムに対して複数の答えの候補を受け付けられるようにしなければなりません。このシリーズでは、そうしたことはしませんが、どうしてもそれが必要ならば、20Q.net のアルゴリズムの使用許諾を受けてそれを行うことができます (「参考文献」を参照)。第 2 回では、このシステムをバックエンドのデータベースと統合し、ユーザーがこのシステムを使っている間にシステムが新しいアイテムを学習できるようにします。
ダウンロード | 内容 | ファイル名 | サイズ | ダウンロード形式 |
|---|
| Part 1 sample code | x-e4xpart1code.zip | 3KB | HTTP |
|---|
参考文献 学ぶために
製品や技術を入手するために
議論するために
著者について  | |  | Nicholas Chase は、Lucent Technologies や Sun Microsystems、Oracle、the Tampa Bay Buccaneers などの会社で Web サイト開発に携わってきました。彼は高校の物理の先生であり、低レベル放射性廃棄物施設の管理者であり、オンライン SF 雑誌の編集者であり、マルチメディアのエンジニアであり、Oracle インストラクターであり、対話型コミュニケーションを提供する会社の最高技術責任者でもあります。また『XML Primer Plus』(Sams 刊) を始めとする何冊かの著書があります。彼は Second Life のコンテンツとアプリケーションの作成を専門とする InterSection Unlimited のパートナーでもあります。in-world では Chase Marellan という名前を使っています。 |
記事の評価
|