情報提供の目的で、この記事では、Riakバージョン2.1.1に基づいて単純なテキストドキュメントの単純なリポジトリを作成し、Riak Search(横綱)を使用してそれらの検索を整理するプロセスについて説明します。 クライアントライブラリとして、 Erlangの公式クライアントが使用されます。
まず、膨大な数のそのようなドキュメントがあると想像してください。
- title-タイトル。
- body-コンテンツ。
- タグ-タグ;
- created_at-作成時間。
- smiles-絵文字の数(プラス、いいね、好きなように)
そして、それらを変更したい膨大な数のユーザー。 誰も気にしないで、始めましょう。
読者はすでにリアクについてある程度の考えを持っているということです。 そうでない場合は、 こことここ 、またはもちろん公式文書を読むのが最善です。
インストールと初期セットアップ
Riak Searchを実行するには、システムにJavaをインストールする必要があります。 Riak自体はHomebrew経由でOSXにインストールでき、必要に応じてErlangが自動的にインストールされます。
brew install riak
トレーニングの目的上、クラスター全体をデプロイすることは意味がありません。1つのノードに制限することができます。そのため、開始する前に最小限の構成のみを実行する必要があります。 構成では、Riak検索をアクティブにする必要があります。
## To enable Search set this 'on'. ## ## Default: off ## ## Acceptable values: ## - on or off search = on
Homeakを使用してRiakをインストールする場合、構成は次のとおりです-/usr/local/Cellar/riak/2.1.1/libexec/etc/riak.conf
また、開いているファイルの制限を増やす必要があります。これを行わないと、起動時に警告が表示されます。 OSX Yosemiteでは、これを行いました:
echo kern.maxfiles=65536 >> /etc/sysctl.conf echo kern.maxfilesperproc=65536 >> /etc/sysctl.conf sudo sysctl -w kern.maxfiles=65536 sudo sysctl -w kern.maxfilesperproc=65536 echo ulimit -n 65536 65536 >> ~/.bash_profile ulimit -n 65536 65536
これで、Riakを開始できます。
riak console
また、別のシェルセッションからテストできます。
riak-admin test
答えは次のようになります:「riak@127.0.0.1」への1回の読み取り/書き込みサイクルが正常に完了しました
インストールと設定の詳細:
Riakデータ型
最終的にRiakが属する一貫したストレージは、いわゆる発生を許可します。 異なるレプリカ上の同じキーの内容が異なる場合のデータのコストが低い状況。 設定に応じて、Riakはベクトルクロックまたはタイムスタンプを使用して競合を自動的に解決しようとするか、使用可能なすべてのバージョン(兄弟)を提供して、値の正しいバージョンを決定する義務をアプリケーションにシフトします。 実際の状況では、ドキュメントがマルチユーザーモードで編集され、複数のノードに複製される場合、競合するデータのマージは非常に困難なタスクになる可能性があります。 この場合、おそらく最適なソリューションはRiakデータ型( CRDTとも呼ばれます )を使用することです。 このテクノロジーにより、特殊なタイプを使用してデータを記述し、クラスターデータの収束の問題の解決を引き受け、競合解決の責任の適用を軽減できます。
Riak Data Typesは現在、次の5種類のCRDTを実装しています。
- flag-ビットフラグ。 利用可能な操作-削除、インストール。 マップ内でのみ使用できます。
- カウンター-カウンター。 利用可能な操作-増加、減少。 また、マップ内でのみ使用できます。
- register-任意の値(文字列として保存);
- set-値のセット。 利用可能な操作-要素の追加、要素の削除。
- map-他のタイプのコンテナ。 内部にフラグ、カウンタ、レジスタ、セット、ネストされたマップを保存できます。 利用可能な操作-フィールドの追加、フィールドの削除、およびそれらのタイプに対応する内部フィールドの操作
これらのタイプに従って、ドキュメントを次の構造を持つマップとして表します。
- タイトル-登録;
- タグ-セット;
- body-登録;
- created_at-登録;
- 笑顔-カウンター
documents-typeというバケットタイプを作成してアクティブ化し、ドキュメントを保存します。
riak-admin bucket-type create documents-type '{"props":{"datatype":"map"}}' riak-admin bucket-type activate documents-type
最終的に整合性のあるRiakデータ型とCRDTの詳細:
- Riak Docs-最終的な整合性 ;
- Riak Docs-競合の解決 。
- Riak Docs-データ型 ;
- の包括的な研究
収束および可換複製データ型-Shapiro、Preguiça、Baquero、およびZawirski
リアック検索
タグ、タイトル、作成日、コンテンツごとにドキュメントの検索を実装したいと考えています。 これを行うために、コードネームYokozunaと呼ばれるRiak Searchテクノロジーを使用します。これは、本質的にRiakリポジトリーとApache Solr検索エンジンの間の中間体です。 Yokuzuna自体は、クラスターの各ノードでSolrを使用して個別のJVMプロセスを起動および監視し、検索クエリとデータ変更をそれに渡します。
Solrがドキュメントのインデックスを作成する方法を知るために、検索スキームを作成する必要があります。 一般に、Riak Searchにはすべての場合にデフォルトのスキームがあります-_yz_defaultは 、開発中に使用するのに便利ですが、作業環境用に独自のものを作成する方が適切です。
既にデータ構造が定義されているため、すぐにスキーマを作成します。 スキームでは、ドキュメントフィールドをリストする必要があります。各フィールドはタイプを示し、インデックスを作成してその値を保存する必要があるかどうかを示し、後で検索結果に返されるようにします。 また、Riak Searchサービスのフィールドをスキームに含める必要があります。 Riakデータ型を使用する場合、それらの型に対応するサフィックスがフィールド名に追加されることに注意してください。 したがって、次の説明が得られます。
<field name="title_register" type="string" indexed="true" stored="false" multiValued="fase" /> <field name="body_register" type="text_ru" indexed="true" stored="false" multiValued="true" /> <field name="tags_set" type="string" indexed="true" stored="false" multiValued="true" /> <field name="created_at_register" type="tdate" indexed="true" stored="false" multiValued="false" omitNorms="true" />
ネタバレの下で、回路ファイルの全内容:
docs_seacrh_schema.xml
<?xml version="1.0" encoding="UTF-8" ?> <schema name="schedule" version="1.5"> <fields> <field name="title_register" type="string" indexed="true" stored="false" multiValued="fase" /> <field name="body_register" type="text_ru" indexed="true" stored="false" multiValued="true" /> <field name="tags_set" type="string" indexed="true" stored="false" multiValued="true" /> <field name="created_at_register" type="tdate" indexed="true" stored="false" multiValued="false" omitNorms="true" /> <!-- --> <dynamicField name="*" type="ignored" /> <!-- Riak Search--> <field name="_yz_id" type="_yz_str" indexed="true" stored="true" multiValued="false" required="true"/> <field name="_yz_ed" type="_yz_str" indexed="true" stored="false" multiValued="false"/> <field name="_yz_pn" type="_yz_str" indexed="true" stored="false" multiValued="false"/> <field name="_yz_fpn" type="_yz_str" indexed="true" stored="false" multiValued="false"/> <field name="_yz_vtag" type="_yz_str" indexed="true" stored="false" multiValued="false"/> <field name="_yz_rk" type="_yz_str" indexed="true" stored="true" multiValued="false"/> <field name="_yz_rt" type="_yz_str" indexed="true" stored="true" multiValued="false"/> <field name="_yz_rb" type="_yz_str" indexed="true" stored="true" multiValued="false"/> <field name="_yz_err" type="_yz_str" indexed="true" stored="false" multiValued="false"/> </fields> <uniqueKey>_yz_id</uniqueKey> <types> <fieldType name="string" class="solr.StrField" sortMissingLast="true" /> <fieldType name="tdate" class="solr.TrieDateField" precisionStep="6" positionIncrementGap="0" sortMissingLast="true" /> <fieldType name="text_ru" class="solr.TextField" positionIncrementGap="100"> <analyzer> <tokenizer class="solr.StandardTokenizerFactory"/> <filter class="solr.LowerCaseFilterFactory"/> <filter class="solr.StopFilterFactory" ignoreCase="true" words="lang/stopwords_ru.txt" format="snowball" /> <filter class="solr.SnowballPorterFilterFactory" language="Russian"/> <!-- less aggressive: <filter class="solr.RussianLightStemFilterFactory"/> --> </analyzer> </fieldType> <fieldtype name="ignored" stored="false" indexed="false" multiValued="true" class="solr.StrField" /> <!-- YZ String: Used for non-analyzed fields --> <fieldType name="_yz_str" class="solr.StrField" sortMissingLast="true" /> </types> </schema>
Riak Searchの詳細:
- Riak Docs-検索の使用 。
- Riak Docs-検索の詳細 。
- Riak Docs-Riakデータ型と検索 。
- Riak Docs-検索スキーマ 。
- Apache Solrリファレンスガイド-ドキュメント、フィールド、およびスキーマ設計
ErlangからRiakにアクセスする
最後に、Erlangのクライアントを使用してノードに接続します。
# : git clone https://github.com/basho/riak-erlang-client.git cd riak-erlang-client/ make cd .. # REPL: erl -pa riak-erlang-client/ebin riak-erlang-client/deps/*/ebin
つなぐ
{ok, RiakPid} = riakc_pb_socket:start_link("127.0.0.1", 8087). % pong = riakc_pb_socket:ping(RiakPid).
検索スキームとインデックスを作成する
{ok, Schema} = file:read_file("docs_search_schema.xml"). ok = riakc_pb_socket:create_search_schema(RiakPid, <<"documents-schema">>, Schema). ok = riakc_pb_socket:create_search_index(RiakPid, <<"documents-index">>, <<"documents-schema">>, []).
バケットを作成して検索インデックスを割り当てる
ok = riakc_pb_socket:set_search_index(RiakPid, {<<"documents-type">>, <<"documents-bucket">>}, <<"documents-index">>).
新しいドキュメントを作成する
Map = riakc_map:new(). % - (register) Map1 = riakc_map:update({<<"title">>, register}, fun(Reg) -> riakc_register:set(<<"DocumentTitle">>, Reg) end, Map). % - (register) Map2 = riakc_map:update({<<"body">>, register}, fun(Reg) -> riakc_register:set(<<"Some Document Body">>, Reg) end, Map1). % - (set) Map3 = riakc_map:update({<<"tags">>, set}, fun(Set) -> Set1 = riakc_set:add_element(<<"Tag One">>, Set), Set2 = riakc_set:add_element(<<"Tag Two">>, Set1), Set2 end, Map2). % - (register) Map4 = riakc_map:update({<<"created_at">>, register}, fun(Reg) -> % C Solr ISO8601. % https://cwiki.apache.org/confluence/display/solr/Working+with+Dates. ISODateFmtStr = "~4.10.0B-~2.10.0B-~2.10.0BT~2.10.0B:~2.10.0B:~2.10.0BZ", {{Year, Month, Day}, {Hour, Min, Sec}} = calendar:universal_time(), ISODate = list_to_binary(io_lib:format(ISODateFmtStr, [Year, Month, Day, Hour, Min, Sec])), riakc_register:set(ISODate, Reg) end, Map3). % MapOperations = riakc_map:to_op(Map4). ok = riakc_pb_socket:update_type(RiakPid, {<<"documents-type">>, <<"documents-bucket">>}, <<"DocumentKey">>, MapOperations).
ドキュメントを検索して取得する
% Riak Client. rr("riak-erlang-client/include/riakc.hrl"). % , {ok, Results} = riakc_pb_socket:search(RiakPid, <<"documents-index">>, <<"title_register:DocumentTitle AND tags_set:\"Tag One\" AND body_register:Some AND created_at_register:[1972-05-20T17:33:18Z TO NOW]">>). % Docs = Results#search_results.docs. lists:foldr(fun({_Index, Doc}, Acc) -> {_, DocumentId} = lists:keyfind(<<"_yz_rk">>, 1, Doc), {ok, {map, Image, _, _, _}} = riakc_pb_socket:fetch_type(RiakPid, {<<"documents-type">>, <<"documents-bucket">>}, DocumentId), Image end, [], Docs).
ドキュメントを変更する
riakc_pb_socket:modify_type(RiakPid, fun(Map) -> % UpdatedMap1 = riakc_map:update({<<"body">>, register}, fun(Register) -> riakc_register:set(<<" ">>, Register) end, Map), % UpdatedMap2 = riakc_map:update({<<"tags">>, set}, fun(Set) -> riakc_set:del_element(<<"Tag One">>, Set) end, UpdatedMap1), % 10 UpdatedMap3 = riakc_map:update({<<"smiles">>, counter}, fun(Counter) -> riakc_counter:increment(10, Counter) end, UpdatedMap2), UpdatedMap3 end, {<<"documents-type">>, <<"documents-bucket">>}, <<"DocumentKey">>, []). % riakc_pb_socket:search(RiakPid, <<"documents-index">>, <<"body_register:\"\"">>).
文書を削除する
riakc_pb_socket:delete(RiakPid, {<<"documents-type">>, <<"documents-bucket">>}, <<"DocumentKey">>). % riakc_pb_socket:search(RiakPid, <<"documents-index">>, <<"body_register:\"\"">>).
クライアントライブラリの操作に関する詳細:
今のところすべてです。 この記事が役に立つことがわかったら、次回は、これらすべてのためにカウボーイベースのWebインターフェイスを作成する方法について説明します。