You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by qi...@apache.org on 2019/09/27 11:06:09 UTC

[incubator-iotdb] branch master updated: [IOTDB-221]Add a python client example (#427)

This is an automated email from the ASF dual-hosted git repository.

qiaojialin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-iotdb.git


The following commit(s) were added to refs/heads/master by this push:
     new 6908460  [IOTDB-221]Add a python client example (#427)
6908460 is described below

commit 6908460f607a2b4c60c3f53ae555cd4907659b67
Author: Jiang Tian <jt...@163.com>
AuthorDate: Fri Sep 27 19:06:04 2019 +0800

    [IOTDB-221]Add a python client example (#427)
    
    * add client-py
---
 .gitignore                      |   3 +-
 client-py/compile.bat           |  28 ++++++++
 client-py/compile.sh            |  28 ++++++++
 client-py/readme.md             |  42 +++++++++++
 client-py/src/client_example.py | 151 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 251 insertions(+), 1 deletion(-)

diff --git a/.gitignore b/.gitignore
index 6691ce4..18a7508 100644
--- a/.gitignore
+++ b/.gitignore
@@ -85,4 +85,5 @@ grafana/data/test.csv
 tsfile/src/test/resources/*.ts
 
 ### Apache release ###
-local-snapshots-dir/
\ No newline at end of file
+local-snapshots-dir/
+venv/
diff --git a/client-py/compile.bat b/client-py/compile.bat
new file mode 100644
index 0000000..a9081c0
--- /dev/null
+++ b/client-py/compile.bat
@@ -0,0 +1,28 @@
+@REM
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements.  See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership.  The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License.  You may obtain a copy of the License at
+@REM
+@REM     http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied.  See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM
+
+@echo off
+set THRIFT_EXE=C:\bin\thrift-0.12.0.exe
+set BAT_DIR=%~dp0
+set THRIFT_SCRIPT=%BAT_DIR%..\service-rpc\src\main\thrift\rpc.thrift
+set THRIFT_OUT=%BAT_DIR%target
+
+rm -rf %THRIFT_OUT%
+mkdir %THRIFT_OUT%
+%THRIFT_EXE% -gen py -out %THRIFT_OUT%  %THRIFT_SCRIPT%
diff --git a/client-py/compile.sh b/client-py/compile.sh
new file mode 100644
index 0000000..628ca82
--- /dev/null
+++ b/client-py/compile.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+export THRIFT_EXE=thrift
+export SH_DIR=$(dirname $0)/
+export THRIFT_SCRIPT=${SH_DIR}../service-rpc/src/main/thrift/rpc.thrift
+export THRIFT_OUT=${SH_DIR}target
+
+rm -rf ${THRIFT_OUT}
+mkdir ${THRIFT_OUT}
+${THRIFT_EXE} -gen py -out ${THRIFT_OUT}  ${THRIFT_SCRIPT}
diff --git a/client-py/readme.md b/client-py/readme.md
new file mode 100644
index 0000000..8b79c94
--- /dev/null
+++ b/client-py/readme.md
@@ -0,0 +1,42 @@
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+
+# introduction
+This is an example of how to connect to IoTDB with python, using the thrift rpc interfaces. Things will be a bit different
+on Linux or Windows, we will introduce how to operate on the two systems separately.
+
+## Prerequisites
+python3.7 or later is preferred.
+
+You have to install Thrift (0.11.0 or later) to compile our thrift file into python code. Below is the official
+tutorial of installation:
+```
+http://thrift.apache.org/docs/install/
+```
+
+## Compile
+If you have added Thrift executable into your path, you may just run `compile.sh` or `compile.bat`, or you will have to
+modify it to set variable `THRIFT_EXE` to point to your executable. This will generate thrift sources under folder `target`,
+you can add it to your `PYTHONPATH` so that you would be able to use the library in your code.
+
+## Example
+We provided an example of how to use the thrift library to connect to IoTDB in `src\client_example.py`, please read it 
+carefully before you write your own code.
diff --git a/client-py/src/client_example.py b/client-py/src/client_example.py
new file mode 100644
index 0000000..05faf83
--- /dev/null
+++ b/client-py/src/client_example.py
@@ -0,0 +1,151 @@
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing,
+#  software distributed under the License is distributed on an
+#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+#  specific language governing permissions and limitations
+#  under the License.
+#
+
+import sys, struct
+sys.path.append("../target")
+
+from thrift.protocol import TBinaryProtocol
+from thrift.transport import TSocket, TTransport
+
+from rpc.TSIService import Client, TSCreateTimeseriesReq, TSInsertionReq, TSBatchInsertionReq, TSExecuteStatementReq,\
+    TS_SessionHandle, TSHandleIdentifier, TSOpenSessionReq, TSQueryDataSet, TSFetchResultsReq, TSCloseOperationReq,\
+    TSCloseSessionReq
+
+TSDataType = {
+    'BOOLEAN' : 0,
+    'INT32' : 1,
+    'INT64' : 2,
+    'FLOAT' : 3,
+    'DOUBLE' : 4,
+    'TEXT' : 5
+}
+
+TSEncoding = {
+    'PLAIN' : 0,
+    'PLAIN_DICTIONARY' : 1,
+    'RLE' : 2,
+    'DIFF' : 3,
+    'TS_2DIFF' : 4,
+    'BITMAP' : 5,
+    'GORILLA' : 6,
+    'REGULAR' : 7
+}
+
+Compressor = {
+    'UNCOMPRESSED' : 0,
+    'SNAPPY' : 1,
+    'GZIP' : 2,
+    'LZO' : 3,
+    'SDT' : 4,
+    'PAA' : 5,
+    'PLA' : 6
+}
+
+
+if __name__ == '__main__':
+    ip = "localhost"
+    port = "6667"
+    username = 'root'
+    password = 'root'
+    # Make socket
+    transport = TSocket.TSocket(ip, port)
+
+    # Buffering is critical. Raw sockets are very slow
+    transport = TTransport.TBufferedTransport(transport)
+
+    # Wrap in a protocol
+    protocol = TBinaryProtocol.TBinaryProtocol(transport)
+
+    # Create a client to use the protocol encoder
+    client = Client(protocol)
+
+    # Connect!
+    transport.open()
+
+    # Authentication
+    client.openSession(TSOpenSessionReq(username=username, password=password))
+
+    # This is necessary for resource control
+    stmtId = client.requestStatementId()
+
+    # These two fields do not matter
+    handle = TS_SessionHandle(TSHandleIdentifier(b'uuid', b'secret'))
+
+    # create a storage group
+    status = client.setStorageGroup("root.group1")
+    print(status.statusType)
+
+    # create timeseries
+    status = client.createTimeseries(TSCreateTimeseriesReq("root.group1.s1", TSDataType['INT64'], TSEncoding['PLAIN'],
+                                                           Compressor['UNCOMPRESSED']))
+    print(status.statusType)
+    status = client.createTimeseries(TSCreateTimeseriesReq("root.group1.s2", TSDataType['INT64'], TSEncoding['PLAIN'],
+                                                           Compressor['UNCOMPRESSED']))
+    print(status.statusType)
+    status = client.createTimeseries(TSCreateTimeseriesReq("root.group1.s3", TSDataType['INT64'], TSEncoding['PLAIN'],
+                                                           Compressor['UNCOMPRESSED']))
+    print(status.statusType)
+
+    # insert a single row
+    status = client.insertRow(TSInsertionReq("root.group1", ["s1", "s2", "s3"], ["1", "11", "111"], 1, 1))
+    print(status.statusType)
+
+    # insert multiple rows, this interface is more efficient
+    values = bytearray()
+    times = bytearray()
+    deviceId = "root.group1"
+    measurements = ["s1", "s2", "s3"]
+    dataSize = 3
+    dataTypes = [TSDataType['INT64'], TSDataType['INT64'], TSDataType['INT64']]
+    # the first 3 belong to 's1', the mid 3 belong to 's2', the last 3 belong to 's3'
+    values.extend(struct.pack('>qqqqqqqqq', 2, 3, 4, 22, 33, 44, 222, 333, 444))
+    times.extend(struct.pack('>qqq', 2, 3, 4))
+    resp = client.insertBatch(TSBatchInsertionReq(deviceId, measurements, values, times,
+                                                  dataTypes, dataSize))
+    status = resp.status
+    print(status.statusType)
+
+    # execute deletion (or other statements)
+    resp = client.executeStatement(TSExecuteStatementReq(handle, "DELETE FROM root.group1 where time < 2"))
+    status = resp.status
+    print(status.statusType)
+
+    # query the data
+    stmt = "SELECT * FROM root.group1"
+    fetchSize = 2
+    # this is also for resource control, make sure different queries will not use the same id at the same time
+    queryId = 1
+    resp = client.executeQueryStatement(TSExecuteStatementReq(handle, stmt))
+    stmtHandle = resp.operationHandle
+    status = resp.status
+    print(status.statusType)
+    while True:
+        rst = client.fetchResults(TSFetchResultsReq(stmt, fetchSize, queryId)).queryDataSet
+        records = rst.records
+        if len(records) == 0:
+            break
+        for record in records:
+            print(record)
+
+    # do not forget to close it when a query is over
+    client.closeOperation(TSCloseOperationReq(stmtHandle, queryId, stmtId))
+
+    # and do not forget to close the session before exiting
+    client.closeSession(TSCloseSessionReq(handle))
+
+