Closed dragon0170 closed 5 years ago
Graph traversal을 위한 machine인 Apache TinkerPop의 Getting Started(http://tinkerpop.apache.org/docs/current/tutorials/getting-started/) 와 Gremlin Console(http://tinkerpop.apache.org/docs/current/tutorials/the-gremlin-console/) Document를 조사하면서 찾은 내용 중 paust-db에서 참고할만한 것들입니다.
gremlin> graph = TinkerFactory.createModern()
==>tinkergraph[vertices:6 edges:6]
gremlin> g = graph.traversal()
==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]
gremlin> g.V()
==>v[1]
==>v[2]
==>v[3]
==>v[4]
==>v[5]
==>v[6]
gremlin> g.V().has('person','name',within('vadas','marko')).values('age')
==>29
==>27
g.V()
, g.V().has().values()
와 같은 query는 사실 traversal을 위한 iterator를 생성하는 것이지 query에 대한 결과값을 가지고 있는 것이 아님. 실제 query 결과값을 얻기 위해서는 해당 iterator를 iterate하여야 함. 하지만 Gremlin console에서는 iterator가 return되는 경우 자동으로 iterate하면서 결과값을 fetch해서 보여주기 때문에 마치 결과값을 바로 출력해주는 것처럼 보임. Gremlin을 console이 아니라 java에서 직접적으로 사용한다면 명시적으로 모두 iterate를 하여야 결과값을 볼 수 있음.
-> 이 구조는 paust-db에서 가져야할 query의 결과와 비슷합니다. paust-db의 query 명령을 통해서는 실제 값을 가져오는 것이 아니라 가져올 주소를 가진 iterator가 생기는 것이고 해당 iterator를 next operation이 들어올 때 실제 값을 fetch해서 사용자에게 보여주게 됩니다. 이런 query-fetch 구조를 paust-db CLI에서 비슷하게 가져가면 좋을 것 같습니다. 다만 console 상에서 자동으로 iterator를 iterate하는 것이 default로 있으면 안될 것 같습니다. 사용자가 하나씩 next명령어를 통해 iterate하고 원하는 데이터라면 나머지 모든 데이터를 iterate 하는 명령어를 입력하는 방식이 좋아보입니다.
-> 이런 구조는 또한 multi query-fetch에 어울릴 것 같습니다. query한 iterator를 하나씩 돌다가 원하는 데이터가 아니면 새롭게 수정된 query를 보내는 구조가 됩니다. 이전 query문에 대한 정보를 재활용할 수 있으면 좋을 것 같네요.g.V().has('person','name',within('vadas','marko')).values('age')
query에는 has()로 데이터의 property에 대해 제한하고 within()으로 'vadas' or 'marko'와 같은 로직도 사용할 수 있음.
-> has()와 같은 query interface는 paust-db의 qualifier에 대한 containing query로 사용하면 좋아보입니다. 그리고 within()과 같은 OR interface도 paust-db query에 필요해 보입니다.저도 node 환경에서 REPL 을 통해서 실험한번해봤습니다. REPL 은 쉽게 implementation 가능한것같아요. 중요한건 인터페이스를 설계하는건데 모델 기반으로 설계를 해야할 것 같습니다. 지금은 httpclient상에서 각 인터페이스 구현부가있고 직접 호출하는 형태인데 이게 아닌 Query, Fetch, 등을 모델로 구현해서 내부의 interface를 통하여 iterator operation 을 구현하면 좋을듯하네요. 아직 어떤 인터페이스 들어갈지 정해진않아서 iterator operation 은 없지만 제 repo에 pdb-tester 에서도 진행하고있으니 같이 설계를 함 해봅시다.
Column 기반 NoSQL database인 HBase의 HBase Shell(https://hbase.apache.org/book.html#shell) Document를 조사하면서 나온 것들 중 paust-db에서 참고할만한 것들입니다. HBase의 console은 Gremlin과는 달리 실제 query보다는 admin이 테스트나 관리를 위해 사용하는 관점을 위주로 만들어진 것 같습니다. 실제로 java application에서 import해서 사용하는 HBase의 코드 구현부를 살펴보면 paust-db Query Interface 구현에 도움이 될 것 같습니다.
hbase(main):021:0> import java.text.SimpleDateFormat
hbase(main):022:0> import java.text.ParsePosition
hbase(main):023:0> SimpleDateFormat.new("yy/MM/dd HH:mm:ss").parse("08/08/16 20:56:29", ParsePosition.new(0)).getTime() => 1218920189000
================================
hbase(main):021:0> import java.util.Date hbase(main):022:0> Date.new(1218920189000).toString() => "Sat Aug 16 20:56:29 UTC 2008"
* HBase console scan interface는 아래와 같습니다.
> Scan a table; pass table name and optionally a dictionary of scanner
specifications. Scanner specifications may include one or more of:
TIMERANGE, FILTER, LIMIT, STARTROW, STOPROW, TIMESTAMP, MAXLENGTH,
or COLUMNS, CACHEIf no columns are specified, all columns will be scanned.
```shell
hbase> scan ‘.META.’, {COLUMNS => ‘info:regioninfo’}
hbase> scan ‘t1’, {COLUMNS => [‘c1’, ‘c2’], LIMIT => 10, STARTROW => ‘xyz’}
hbase> scan ‘t1’, {COLUMNS => ‘c1’, TIMERANGE => [1303668804, 1303668904]}
hbase> scan ‘t1’, {FILTER => “(PrefixFilter (‘row2’) AND
(QualifierFilter (>=, ‘binary:xyz’))) AND (TimestampsFilter ( 123, 456))”}
hbase> scan ‘t1’, {FILTER =>
org.apache.hadoop.hbase.filter.ColumnPaginationFilter.new(1, 0)}
hbase(main):007 > t = create 't', 'f'
0 row(s) in 1.0970 seconds
=> Hbase::Table - t hbase(main):008 > t.put 'r', 'f', 'v' 0 row(s) in 0.0640 seconds hbase(main):009 > t.scan ROW COLUMN+CELL r column=f:, timestamp=1331865816290, value=v 1 row(s) in 0.0110 seconds hbase(main):010:0> t.describe DESCRIPTION ENABLED 't', {NAME => 'f', DATA_BLOCKENCODING => 'NONE', BLOOMFILTER => 'ROW', REPLICATION true SCOPE => '0', VERSIONS => '1', COMPRESSION => 'NONE', MIN_VERSIONS => '0', TTL => '2 147483647', KEEP_DELETED_CELLS => 'false', BLOCKSIZE => '65536', IN_MEMORY => 'false ', BLOCKCACHE => 'true'} 1 row(s) in 0.0210 seconds hbase(main):038:0> t.disable 0 row(s) in 6.2350 seconds hbase(main):039:0> t.drop 0 row(s) in 0.2340 seconds
==============================
hbase(main):011 > create 't','f' 0 row(s) in 1.2500 seconds
=> Hbase::Table - t hbase(main):012:0> tab = get_table 't' 0 row(s) in 0.0010 seconds
=> Hbase::Table - t hbase(main):013:0> tab.put 'r1' ,'f', 'v' 0 row(s) in 0.0100 seconds hbase(main):014:0> tab.scan ROW COLUMN+CELL r1 column=f:, timestamp=1378473876949, value=v 1 row(s) in 0.0240 seconds hbase(main):015:0>
https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/package-summary.html#package.description 에 있는 Example API Usage 참고
https://www.datastax.com/wp-content/uploads/2016/10/bytecode-to-execution.png 참고
ref: https://github.com/paust-team/paust-db/issues/145#issuecomment-475202619, #160
paust-db의 query interface를 timeseries database에 적절하게 설계하기위해 다른 NoSQL database의 query interface design을 우선 찾아보려고 합니다.