如何通过 swi prolog 连接到 MongoDB 服务器?
How to connect to MongoDB server via swi prolog?
我想在 Prolog 和 MongoDB 之间实现一个 API,经过一些研究,第一个障碍是连接到 MongoDB 服务器。我知道已经有 API prolongo 所以我试图理解它,但我没有。我是 Prolog 的新手,所以我的问题是:实际连接到 MongoDB 服务器的位置在哪里?
已编辑:
我已经理解了更多的代码,但我遇到了一个我无法解释的错误:
所以这是 mongo_connection.pl 的代码:
:- module(_, [
host/1,
port/1
]).
:- include(include/common).
%% host(?Host) is semidet.
%
% True if Host is the default hostname used by MongoDB.
host(localhost).
%% port(?Port) is semidet.
%
% True if Port is the default port used by MongoDB.
port(27017).
/** <module> Connection handling and response parsing.
*/
:- module(_, [
new_connection/1,
new_connection/3,
free_connection/1,
get_database/3,
send_to_server/2,
read_reply/4
]).
:- include(include/common).
%% new_connection(-Connection) is det.
%% new_connection(+Host, +Port, -Connection) is det.
%
% True if Connection represents an opaque handle to a new MongoDB
% server connection. Default values (see mongo_defaults) are used unless
% Host and Port are provided.
new_connection(Connection) :-
mongo_defaults:host(Host),
mongo_defaults:port(Port),
new_connection(Host, Port, Connection).
new_connection(Host, Port, Connection) :-
mongo_socket:new_socket(Host, Port, Socket),
Connection = connection(Socket).
connection_socket(Connection, Socket) :-
mongo_util:get_nth1_arg(Connection, 1, Socket).
%% free_connection(+Connection) is det.
%
% Frees any resources associated with the Connection handle,
% rendering it unusable.
free_connection(Connection) :-
connection_socket(Connection, Socket),
mongo_socket:free_socket(Socket).
%% get_database(+Connection, +DatabaseName, -Database) is det.
%
% True if Database is a handle to the database called DatabaseName
% on Connection. No communication is performed, so the actual database
% might or might not already exist.
get_database(Connection, DatabaseName, Database) :-
mongo_database:new_database(Connection, DatabaseName, Database).
%% send_to_server(+Connection, +Bytes) is det.
%
% True if Bytes are sent over Connection.
send_to_server(Connection, Bytes) :-
connection_socket(Connection, Socket),
mongo_socket:send_bytes(Socket, Bytes).
%% read_reply(+Connection, -Header, -Info, -Docs) is det.
%
% True if Header, Info and Docs together represent the next message
% received over Connection. Blocks until a message is completely read.
%
% Header is the structure header(MessageLength,RequestId,ResponseTo,OpCode)
% where:
% - MessageLength is the total number of bytes comprising the message
% - RequestId is the ID of this message (unused)
% - ResponseTo is the ID of the query that triggered this response (unused)
% - OpCode is the code signifying that this is a response (always 1)
%
% Info is the structure info(Flags,CursorId,StartingFrom,NumberReturned)
% where:
% - Flags is the bitmask of flags set for this response
% - CursorId is the cursor ID of this response
% - StartingFrom is the query offset of the first document in Docs
% - NumberReturned is the number of documents in Docs
read_reply(Connection, Header, Info, Docs) :-
connection_socket(Connection, Socket),
read_response_bytes(Socket, Bytes),
parse_response(Bytes, Header, Info, Docs).
read_response_bytes(Socket, [B0,B1,B2,B3|Bytes]) :-
read_message_length(Socket, [B0,B1,B2,B3], TotalLength),
read_rest_of_message(Socket, TotalLength, Bytes).
read_message_length(Socket, Bytes, Length) :-
mongo_socket:receive_n_bytes(Socket, 4, Bytes),
bson_bits:integer_bytes(Length, 4, little, Bytes).
read_rest_of_message(Socket, TotalLength, Bytes) :-
LengthRest is TotalLength - 4,
mongo_socket:receive_n_bytes(Socket, LengthRest, Bytes).
parse_response(Bytes, Header, Info, Docs) :-
% inspect_response_bytes(Bytes), % For debugging.
phrase(parse_response_meta(Header, Info), Bytes, RestBytes),
parse_response_docs(RestBytes, Docs).
parse_response_meta(Header, Info) -->
parse_response_header(Header),
parse_response_info(Info).
parse_response_header(Header) -->
{ Header = header(MessageLength,RequestId,ResponseTo,OpCode) },
mongo_bytes:int32(MessageLength),
mongo_bytes:int32(RequestId),
mongo_bytes:int32(ResponseTo),
mongo_bytes:int32(OpCode).
parse_response_info(Info) -->
{ Info = info(Flags,CursorId,StartingFrom,NumberReturned) },
mongo_bytes:int32(Flags),
mongo_bytes:int64(CursorId),
mongo_bytes:int32(StartingFrom),
mongo_bytes:int32(NumberReturned).
parse_response_docs(Bytes, Docs) :-
bson:docs_bytes(Docs, Bytes).
这里是mongo_socket.pl的代码:
:- module(_, [
new_socket/3,
free_socket/1,
send_bytes/2,
receive_n_bytes/3
]).
:- include(include/common).
%% new_socket(+Host, +Port, -Socket) is det.
%
% True if Socket is a new TCP socket connected to Host:Port.
%
% @throws mongo_error(Description, [SocketException])
new_socket(Host, Port, Socket) :-
setup_call_catcher_cleanup(
socket:tcp_socket(SocketId),
socket:tcp_connect(SocketId, Host:Port, ReadStream, WriteStream),
exception(SocketException),
close_socket_and_throw(SocketId, SocketException)),
Socket = socket(ReadStream,WriteStream).
close_socket_and_throw(SocketId, Exception) :-
socket:tcp_close_socket(SocketId),
throw(mongo_error('could not connect to server', [Exception])).
socket_read(Socket, ReadStream) :-
mongo_util:get_nth1_arg(Socket, 1, ReadStream).
socket_write(Socket, WriteStream) :-
mongo_util:get_nth1_arg(Socket, 2, WriteStream).
%% free_socket(+Socket) is det.
%
% Frees any resources associated with Socket, rendering it unusable.
free_socket(Socket) :-
socket_read(Socket, ReadStream),
socket_write(Socket, WriteStream),
core:close(ReadStream, [force(true)]),
core:close(WriteStream, [force(true)]).
%% send_bytes(+Socket, +Bytes) is det.
%
% True if Bytes are sent (and flushed) over Socket.
send_bytes(Socket, Bytes) :-
socket_write(Socket, WriteStream),
send_bytes_and_flush(Bytes, WriteStream).
send_bytes_and_flush(Bytes, WriteStream) :-
core:format(WriteStream, '~s', [Bytes]),
core:flush_output(WriteStream).
%% receive_n_bytes(+Socket, +N, -Bytes) is det.
%
% True if Bytes is the next N bytes received over Socket.
receive_n_bytes(Socket, N, Bytes) :-
socket_read(Socket, ReadStream),
receive_n_bytes_aux(ReadStream, N, Bytes).
receive_n_bytes_aux(_ReadStream, 0, []) :- !.
receive_n_bytes_aux(ReadStream, N, [Byte|Bytes]) :-
core:get_byte(ReadStream, Byte),
N1 is N - 1,
receive_n_bytes_aux(ReadStream, N1, Bytes).
所以用线
socket:tcp_socket(SocketId),
socket:tcp_connect(SocketId, Host:Port, ReadStream, WriteStream),..
Prolog 创建一个 INET-domain stream-socket。我正在使用 MS-Windows,如果套接字库尚未初始化,这也会初始化库。
但是我收到这个错误:
所以这是我的问题:
- 我是否尝试与错误的文件建立新连接?
- 应该自动加载套接字库,还是我必须将 prolongo 文件放入路径“C:\Program Files\swipl\library”?
- 如何解释上面这个错误?
ODBC 是 SWI Prolog 连接到任何数据库的方式。我刚刚再次完成了将 SWI Prolog 链接到 Postgresql 的过程,它可能很繁琐。
首先,您需要在 swipl 命令行检查一下:
use_module(library(odbc)).
如果你得到 错误:source_sink `library(odbc)' 不存在(就像我刚刚在新的 Arch Linux 安装上所做的那样) ,缺少 SWI Prolog 所需的驱动程序。在 Linux 系统上,这意味着您需要安装 unixodbc。我从源代码构建 SWI Prolog,如果系统中有支持的 ODBC 库,ODBC 会自动包含。
下一部分是为您的数据库安装 ODBC 支持(Google 发现 https://www.mongodb.com/blog/post/odbc-driver-for-the-mongodb-connector-for-business-intelligence,但我没有使用 MongoDB 的经验)。
然后您需要配置 ODBC,这在 Linux 上涉及创建一个 ~/.odbc.ini 文件。我不使用 Windows,所以不知道在那里该怎么做。我写了一些关于如何让 Postgresql 和 SWI Prolog 在 https://github.com/roblaing/swipl-webapp-howto/tree/master/unit3
进行通信的笔记
我想在 Prolog 和 MongoDB 之间实现一个 API,经过一些研究,第一个障碍是连接到 MongoDB 服务器。我知道已经有 API prolongo 所以我试图理解它,但我没有。我是 Prolog 的新手,所以我的问题是:实际连接到 MongoDB 服务器的位置在哪里?
已编辑: 我已经理解了更多的代码,但我遇到了一个我无法解释的错误:
所以这是 mongo_connection.pl 的代码:
:- module(_, [
host/1,
port/1
]).
:- include(include/common).
%% host(?Host) is semidet.
%
% True if Host is the default hostname used by MongoDB.
host(localhost).
%% port(?Port) is semidet.
%
% True if Port is the default port used by MongoDB.
port(27017).
/** <module> Connection handling and response parsing.
*/
:- module(_, [
new_connection/1,
new_connection/3,
free_connection/1,
get_database/3,
send_to_server/2,
read_reply/4
]).
:- include(include/common).
%% new_connection(-Connection) is det.
%% new_connection(+Host, +Port, -Connection) is det.
%
% True if Connection represents an opaque handle to a new MongoDB
% server connection. Default values (see mongo_defaults) are used unless
% Host and Port are provided.
new_connection(Connection) :-
mongo_defaults:host(Host),
mongo_defaults:port(Port),
new_connection(Host, Port, Connection).
new_connection(Host, Port, Connection) :-
mongo_socket:new_socket(Host, Port, Socket),
Connection = connection(Socket).
connection_socket(Connection, Socket) :-
mongo_util:get_nth1_arg(Connection, 1, Socket).
%% free_connection(+Connection) is det.
%
% Frees any resources associated with the Connection handle,
% rendering it unusable.
free_connection(Connection) :-
connection_socket(Connection, Socket),
mongo_socket:free_socket(Socket).
%% get_database(+Connection, +DatabaseName, -Database) is det.
%
% True if Database is a handle to the database called DatabaseName
% on Connection. No communication is performed, so the actual database
% might or might not already exist.
get_database(Connection, DatabaseName, Database) :-
mongo_database:new_database(Connection, DatabaseName, Database).
%% send_to_server(+Connection, +Bytes) is det.
%
% True if Bytes are sent over Connection.
send_to_server(Connection, Bytes) :-
connection_socket(Connection, Socket),
mongo_socket:send_bytes(Socket, Bytes).
%% read_reply(+Connection, -Header, -Info, -Docs) is det.
%
% True if Header, Info and Docs together represent the next message
% received over Connection. Blocks until a message is completely read.
%
% Header is the structure header(MessageLength,RequestId,ResponseTo,OpCode)
% where:
% - MessageLength is the total number of bytes comprising the message
% - RequestId is the ID of this message (unused)
% - ResponseTo is the ID of the query that triggered this response (unused)
% - OpCode is the code signifying that this is a response (always 1)
%
% Info is the structure info(Flags,CursorId,StartingFrom,NumberReturned)
% where:
% - Flags is the bitmask of flags set for this response
% - CursorId is the cursor ID of this response
% - StartingFrom is the query offset of the first document in Docs
% - NumberReturned is the number of documents in Docs
read_reply(Connection, Header, Info, Docs) :-
connection_socket(Connection, Socket),
read_response_bytes(Socket, Bytes),
parse_response(Bytes, Header, Info, Docs).
read_response_bytes(Socket, [B0,B1,B2,B3|Bytes]) :-
read_message_length(Socket, [B0,B1,B2,B3], TotalLength),
read_rest_of_message(Socket, TotalLength, Bytes).
read_message_length(Socket, Bytes, Length) :-
mongo_socket:receive_n_bytes(Socket, 4, Bytes),
bson_bits:integer_bytes(Length, 4, little, Bytes).
read_rest_of_message(Socket, TotalLength, Bytes) :-
LengthRest is TotalLength - 4,
mongo_socket:receive_n_bytes(Socket, LengthRest, Bytes).
parse_response(Bytes, Header, Info, Docs) :-
% inspect_response_bytes(Bytes), % For debugging.
phrase(parse_response_meta(Header, Info), Bytes, RestBytes),
parse_response_docs(RestBytes, Docs).
parse_response_meta(Header, Info) -->
parse_response_header(Header),
parse_response_info(Info).
parse_response_header(Header) -->
{ Header = header(MessageLength,RequestId,ResponseTo,OpCode) },
mongo_bytes:int32(MessageLength),
mongo_bytes:int32(RequestId),
mongo_bytes:int32(ResponseTo),
mongo_bytes:int32(OpCode).
parse_response_info(Info) -->
{ Info = info(Flags,CursorId,StartingFrom,NumberReturned) },
mongo_bytes:int32(Flags),
mongo_bytes:int64(CursorId),
mongo_bytes:int32(StartingFrom),
mongo_bytes:int32(NumberReturned).
parse_response_docs(Bytes, Docs) :-
bson:docs_bytes(Docs, Bytes).
这里是mongo_socket.pl的代码:
:- module(_, [
new_socket/3,
free_socket/1,
send_bytes/2,
receive_n_bytes/3
]).
:- include(include/common).
%% new_socket(+Host, +Port, -Socket) is det.
%
% True if Socket is a new TCP socket connected to Host:Port.
%
% @throws mongo_error(Description, [SocketException])
new_socket(Host, Port, Socket) :-
setup_call_catcher_cleanup(
socket:tcp_socket(SocketId),
socket:tcp_connect(SocketId, Host:Port, ReadStream, WriteStream),
exception(SocketException),
close_socket_and_throw(SocketId, SocketException)),
Socket = socket(ReadStream,WriteStream).
close_socket_and_throw(SocketId, Exception) :-
socket:tcp_close_socket(SocketId),
throw(mongo_error('could not connect to server', [Exception])).
socket_read(Socket, ReadStream) :-
mongo_util:get_nth1_arg(Socket, 1, ReadStream).
socket_write(Socket, WriteStream) :-
mongo_util:get_nth1_arg(Socket, 2, WriteStream).
%% free_socket(+Socket) is det.
%
% Frees any resources associated with Socket, rendering it unusable.
free_socket(Socket) :-
socket_read(Socket, ReadStream),
socket_write(Socket, WriteStream),
core:close(ReadStream, [force(true)]),
core:close(WriteStream, [force(true)]).
%% send_bytes(+Socket, +Bytes) is det.
%
% True if Bytes are sent (and flushed) over Socket.
send_bytes(Socket, Bytes) :-
socket_write(Socket, WriteStream),
send_bytes_and_flush(Bytes, WriteStream).
send_bytes_and_flush(Bytes, WriteStream) :-
core:format(WriteStream, '~s', [Bytes]),
core:flush_output(WriteStream).
%% receive_n_bytes(+Socket, +N, -Bytes) is det.
%
% True if Bytes is the next N bytes received over Socket.
receive_n_bytes(Socket, N, Bytes) :-
socket_read(Socket, ReadStream),
receive_n_bytes_aux(ReadStream, N, Bytes).
receive_n_bytes_aux(_ReadStream, 0, []) :- !.
receive_n_bytes_aux(ReadStream, N, [Byte|Bytes]) :-
core:get_byte(ReadStream, Byte),
N1 is N - 1,
receive_n_bytes_aux(ReadStream, N1, Bytes).
所以用线
socket:tcp_socket(SocketId),
socket:tcp_connect(SocketId, Host:Port, ReadStream, WriteStream),..
Prolog 创建一个 INET-domain stream-socket。我正在使用 MS-Windows,如果套接字库尚未初始化,这也会初始化库。
但是我收到这个错误:
所以这是我的问题:
- 我是否尝试与错误的文件建立新连接?
- 应该自动加载套接字库,还是我必须将 prolongo 文件放入路径“C:\Program Files\swipl\library”?
- 如何解释上面这个错误?
ODBC 是 SWI Prolog 连接到任何数据库的方式。我刚刚再次完成了将 SWI Prolog 链接到 Postgresql 的过程,它可能很繁琐。
首先,您需要在 swipl 命令行检查一下:
use_module(library(odbc)).
如果你得到 错误:source_sink `library(odbc)' 不存在(就像我刚刚在新的 Arch Linux 安装上所做的那样) ,缺少 SWI Prolog 所需的驱动程序。在 Linux 系统上,这意味着您需要安装 unixodbc。我从源代码构建 SWI Prolog,如果系统中有支持的 ODBC 库,ODBC 会自动包含。
下一部分是为您的数据库安装 ODBC 支持(Google 发现 https://www.mongodb.com/blog/post/odbc-driver-for-the-mongodb-connector-for-business-intelligence,但我没有使用 MongoDB 的经验)。
然后您需要配置 ODBC,这在 Linux 上涉及创建一个 ~/.odbc.ini 文件。我不使用 Windows,所以不知道在那里该怎么做。我写了一些关于如何让 Postgresql 和 SWI Prolog 在 https://github.com/roblaing/swipl-webapp-howto/tree/master/unit3
进行通信的笔记