LoginSignup
20
23

More than 5 years have passed since last update.

PrologなNoSQLサーバを立てる

Last updated at Posted at 2015-01-07

はじめに

なんの需要があるかわかりませんが,あるとき突然,Prologサーバを立てたくなる時があります.例えば,サーバ側では,大量の述語をデータベース代わりに持っていて,TCP通信でクエリを投げてその結果を得ることができたらな,と思うわけです.

データとして以下の述語を与えます.

tag_name(oppai).
tag_name(bikini).

picture(aaa).
picture(bbb).
picture(ccc).

tag(X, Y) :- tag_name(X), picture(Y).

tag(oppai, aaa).
tag(oppai, bbb).
tag(oppai, ccc).
tag(bikini, bbb).
tag(bikini, ccc).

tagの第一引数はタグの名前で,第二引数は画像の名前です.特定のタグの付けられた画像を検索する場合,以下の述語で推定することができます.

tag(bikini, X).
% X = tag(bikini, bbb);
% X = tag(bikini, ccc);

速度的に何千万件のデータを扱うのは難しいかもしれませんが,NoSQLの試みとして面白いなと思ったわけです.

サーバ側の実装

サーバ側で起動しておくPrologのソースコードです.

create_server(Port) :-
    tcp_socket(Socket),
    tcp_bind(Socket, Port),
    tcp_listen(Socket, 5),
    tcp_open_socket(Socket, AcceptFd, _),
    dispatch(AcceptFd).

dispatch(AcceptFd) :-
    tcp_accept(AcceptFd, Socket, _Peer),
    thread_create(process_client(Socket, Peer), _,
        [ detached(true)
        ]),
    dispatch(AcceptFd).

process_client(Socket, Peer) :-
    setup_call_cleanup(tcp_open_socket(Socket, In, Out),
       handle_service(In, Out),
       close_connection(In, Out)).

close_connection(In, Out) :-
    close(In, [force(true)]),
    close(Out, [force(true)]).

handle_service(In, Out) :-
    read(In, Chars),
    findall(Chars, Chars, L),
    write(Out, L),
    writeln(L).

% 以下,データベース用の述語を定義する

Prologのコンソールから,以下のコードを実行すると,ポート3333でListenします.

create_server(3333).

クライアント側の実装

クライアント側はTCP通信でポートを指定して接続します.ここではRubyですが,他の言語については頑張って実装してください.

require "socket"

while gets
  s = TCPSocket.open("localhost", 3333)
  s.write($_)
  puts s.gets
  s.close
end

このソースコードを実行すると,TCPソケットを開いてユーザからの入力を待ちます.Prologの述語を書くと,localhostで実行しているPrologサーバに述語を送信し,その内容を推定し,結果を返します.

tag(X,Y).
[tag(oppai,a),tag(oppai,b),tag(oppai,c),tag(bikini,b),tag(bikini,c)]

Prologの将来

Prologの推定は,他のRDBMSやNoSQLにはない機能です.似たような処理は確かに他でも書くことは可能ですが,Prologほど簡潔には書けません.例えば,SQLであれば以下の様なクエリになると思います.

select picture.name from picture, tag where tag.picture_id = picture.id;

Prologと比べるといかに冗長であるということがわかると思います.

また,先のデータベース用の述語では,tag_nameとpictureを定義していましたが,別にきちんとスキーマが決まっていれば,この2種類の述語は必要ありません.その点で,NoSQL並みの柔軟さがあり,(使い方さえわかれば)簡潔なクエリを投げることが出来ます.

あとはほぼ速度やアーキテクチャの問題なので,いつかPrologがNoSQLで脚光を浴びるんじゃないかなぁとか思うのですがどうでしょう? Prologプログラミング自体は悟りが必要なので難しいかもしれませんが,シンプルな方法であれば十分に使用に耐えられると思います.

20
23
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
23