ããã«ã¡ã¯ãã¿ããªã ç§ãã¡ã¯ãªãã©ã€ã³ãã©ãã£ãã¯åæã®ããã®è£œåãéçºããŠããŸãã ãã®ãããžã§ã¯ãã«ã¯ãå°åéã®èšªåè ã®ã«ãŒãã®çµ±èšåæã«é¢é£ããã¿ã¹ã¯ããããŸãã
ãã®ã¿ã¹ã¯ã®äžç°ãšããŠããŠãŒã¶ãŒã¯æ¬¡ã®ã¿ã€ãã®ã·ã¹ãã ã¯ãšãªãå®è¡ã§ããŸãã
- ãšãªã¢ãAããããšãªã¢ãBãã«ééãã蚪åè ã®æ°ã
- ãšãªã¢ãAããããšãªã¢ãCããçµç±ãããšãªã¢ãDããçµç±ããŠãšãªã¢ãBãã«ç§»åãã蚪åè ã®æ°ã
- ç¹å®ã®ã¿ã€ãã®èšªåè ããšãªã¢ãAããããšãªã¢ãBãã«ç§»åããã®ã«ã©ããããæéãããããŸãããã
ããã³åæ§ã®åæã¯ãšãªãå€æ°ãããŸãã
ãšãªã¢éã®èšªåè ã®ç§»åã¯æåã°ã©ãã§ãã ã€ã³ã¿ãŒããããèªãã§ãããšãã°ã©ã DBMS ã¯åæã¬ããŒãã«ã䜿çšãããŠããããšãããããŸããã ç§ã¯ãã°ã©ã DBMS ããã®ãããªã¯ãšãªã«ã©ã®ããã«å¯ŸåŠããããç¥ããããšæã£ãŠããŸãã (TL; DR; äžå®å šã«ïŒã
DBMS ã䜿çšããããšã«ããŸãã
- BerkeleyDB ã¹ãã¬ãŒãž ããã¯ãšã³ããApache CassandraãScyllaã
- è€éãªã€ã³ããã¯ã¹ã¯ LuceneãElasticsearchãSolr ã«ä¿åã§ããŸãã
JanusGraph ã®äœæè ã¯ãJanusGraph ã OLTP ãš OLAP ã®äž¡æ¹ã«é©ããŠãããšæžããŠããŸãã
ç§ã¯ BerkeleyDBãApache CassandraãScyllaãES ã䜿ã£ãŠããŸããããããã®è£œåã¯ç§ãã¡ã®ã·ã¹ãã ã§ãã䜿çšãããŠããããããã®ã°ã©ã DBMS ã®ãã¹ãã«ã€ããŠã¯æ¥œèŠ³çã§ããã RocksDB ã§ã¯ãªã BerkeleyDB ãéžæããã®ã¯å¥åŠã«æããŸãããããããããã©ã³ã¶ã¯ã·ã§ã³èŠä»¶ã«ãããã®ã§ãã ãããã®å Žåã§ããã¹ã±ãŒã©ãã«ãªè£œåã®äœ¿çšã®ããã«ã¯ãCassandra ãŸã㯠Scylla ã®ããã¯ãšã³ãã䜿çšããããšããå§ãããŸãã
Neo4j ã¯èæ ®ããŸããã§ãããã¯ã©ã¹ã¿ãªã³ã°ã«ã¯åçšããŒãžã§ã³ãå¿ èŠã§ããã€ãŸãããã®è£œåã¯ãªãŒãã³ãœãŒã¹ã§ã¯ãªãããã§ãã
ã°ã©ã DBMS ã¯ããã°ã©ãã«èŠããå Žåã¯ãã°ã©ãã®ããã«æ±ããŸããããšèšããŸãã - çŸããïŒ
ãŸããã°ã©ã DBMS ã®èŠç¯ã«åŸã£ãŠæ£ç¢ºã«äœæãããã°ã©ããæããŸããã
æ¬è³ªã¯ããã Zone
, ãšãªã¢ã®è²¬ä»»è
ã§ãã ãã ZoneStep
ããã«å±ããŸã Zone
ããããŠåœŒã¯ãããåç
§ããŸãã æ¬è³ªã«ã€ã㊠Area
, ZoneTrack
, Person
泚æããªãã§ãã ããããããã¯ãã¡ã€ã³ã«å±ããŠããããã¹ãã®äžéšãšã¯ã¿ãªãããŸããã ãã®ãããªã°ã©ãæ§é ã®ãã§ãŒã³æ€çŽ¢ã¯ãšãªã¯ãå
šäœãšããŠæ¬¡ã®ããã«ãªããŸãã
g.V().hasLabel('Zone').has('id',0).in_()
.repeat(__.out()).until(__.out().hasLabel('Zone').has('id',19)).count().next()
ãã·ã¢èªã§ã¯æ¬¡ã®ããã«ãªããŸããID=0 ã®ãŸãŒã³ãèŠã€ãããšããžãããã«åãããã¹ãŠã®é ç¹ (ZoneStep) ãååŸãããŸãŒã³ãžã®ãšããžããã ZoneStep ãèŠã€ãããŸã§æ»ããã«èžã¿ã€ããŸãã ID=19ããã®ãããªãã§ãŒã³ã®æ°ãæ°ããŸãã
ç§ã¯ã°ã©ãæ€çŽ¢ã®è€éãããã¹ãŠç¥ã£ãŠããã€ããã¯ãããŸãããããã®ã¯ãšãªã¯ãã®æ¬ã«åºã¥ããŠçæãããŸãã (
BerkeleyDB ããã¯ãšã³ãã䜿çšããŠãé·ã 50 ïœ 3 ãã€ã³ãã® 20 ãã©ãã¯ã JanusGraph ã°ã©ã ããŒã¿ããŒã¹ã«ããŒããã次ã«åŸã£ãŠã€ã³ããã¯ã¹ãäœæããŸããã
Python ããŠã³ããŒã ã¹ã¯ãªãã:
from random import random
from time import time
from init import g, graph
if __name__ == '__main__':
points = []
max_zones = 19
zcache = dict()
for i in range(0, max_zones + 1):
zcache[i] = g.addV('Zone').property('id', i).next()
startZ = zcache[0]
endZ = zcache[max_zones]
for i in range(0, 10000):
if not i % 100:
print(i)
start = g.addV('ZoneStep').property('time', int(time())).next()
g.V(start).addE('belongs').to(startZ).iterate()
while True:
pt = g.addV('ZoneStep').property('time', int(time())).next()
end_chain = random()
if end_chain < 0.3:
g.V(pt).addE('belongs').to(endZ).iterate()
g.V(start).addE('goes').to(pt).iterate()
break
else:
zone_id = int(random() * max_zones)
g.V(pt).addE('belongs').to(zcache[zone_id]).iterate()
g.V(start).addE('goes').to(pt).iterate()
start = pt
count = g.V().count().next()
print(count)
SSD äžã« 4 ã³ã¢ãš 16 GB RAM ãæèŒãã VM ã䜿çšããŸããã JanusGraph ã¯æ¬¡ã®ã³ãã³ãã䜿çšããŠãããã€ãããŸããã
docker run --name janusgraph -p8182:8182 janusgraph/janusgraph:latest
ãã®å Žåãå®å šäžèŽæ€çŽ¢ã«äœ¿çšãããããŒã¿ãšã€ã³ããã¯ã¹ã¯ BerkeleyDB ã«ä¿åãããŸãã å ã»ã©ã®ãªã¯ãšã¹ããå®è¡ãããšãæ°åç§ã®æéãåãåããŸããã
äžèšã® 4 ã€ã®ã¹ã¯ãªããã䞊è¡ããŠå®è¡ããããšã§ãDocker ãã°ã« Java ã¹ã¿ãã¯ãã¬ãŒã¹ (ãããŠç§ãã¡ã¯çãJava ã¹ã¿ãã¯ãã¬ãŒã¹ãèªãã®ã倧奜ãã§ã) ã®éœæ°ãªã¹ããªãŒã ãåããã«ããã£ã« DBMS ãå€ããããšãã§ããŸããã
å°ãèããçµæãã°ã©ãå³ã次ã®ããã«åçŽåããããšã«ããŸããã
ãšã³ãã£ãã£å±æ§ã«ããæ€çŽ¢ã®æ¹ãããšããžã«ããæ€çŽ¢ãããé«éã§ãããšå€æããŸãã ãã®çµæãç§ã®ãªã¯ãšã¹ãã¯æ¬¡ã®ããã«ãªããŸããã
g.V().hasLabel('ZoneStep').has('id',0).repeat(__.out().simplePath()).until(__.hasLabel('ZoneStep').has('id',19)).count().next()
ãã·ã¢èªã§ã¯æ¬¡ã®ããã«ãªããŸããID=0 ã® ZoneStep ãèŠã€ããŠãID=19 ã® ZoneStep ãèŠã€ãããŸã§æ»ããã«èžã¿ç¶ãããã®ãããªãã§ãŒã³ã®æ°ãæ°ããŸãã
ãŸããäžèŠãªæ¥ç¶ãäœæããªãããã«ãå±æ§ã«éå®ããŠäžèšã®èªã¿èŸŒã¿ã¹ã¯ãªãããç°¡çŽ åããŸããã
ãªã¯ãšã¹ããå®äºãããŸã§ã«ãŸã æ°ç§ããããŸãããããããªãçš®é¡ã®ã¢ããã㯠ãªã¯ãšã¹ãã®ç®çã«ããŸã£ããé©ããŠããªããããããã¯ç§ãã¡ã®ã¿ã¹ã¯ãšããŠã¯ãŸã£ããåãå ¥ããããŸããã§ããã
æéã® Cassandra å®è£ ãšã㊠Scylla ã䜿çšã㊠JanusGraph ããããã€ããããšããŸããããããã倧ããªããã©ãŒãã³ã¹ã®å€åã«ã¯ã€ãªãããŸããã§ããã
ãã®ããããã°ã©ãã®ããã«èŠãããã«ãããããããã°ã©ã DBMS ã«é«éã«åŠçãããããšãã§ããŸããã§ããã äœãããããªãããšããããJanusGraph ã䜿ãã°ã»ãã®äžç¬ã§ãã®æ€çŽ¢ãå®è¡ã§ããã ãããšååã«æ³å®ããŠããŸããããç§ã«ã¯ãããã§ããŸããã§ããã
ãã®åé¡ã¯ãŸã 解決ããå¿ èŠããããããããŒãã«ã® JOIN ãšããããã«ã€ããŠèãå§ããŸãããããã¯ãåªé ãã®ç¹ã§æ¥œèŠ³çãªèŠæ¹ãåºæ¿ãããã®ã§ã¯ãããŸããã§ããããå®éã«ã¯å®å šã«å®è¡å¯èœãªãªãã·ã§ã³ã§ããå¯èœæ§ããããŸãã
ç§ãã¡ã®ãããžã§ã¯ãã§ã¯ãã§ã« Apache ClickHouse ã䜿çšããŠããããããã®åæ DBMS ã§ç 究ããã¹ãããããšã«ããŸããã
ç°¡åãªã¬ã·ãã䜿çšã㊠ClickHouse ããããã€ããŸãã
sudo docker run -d --name clickhouse_1
--ulimit nofile=262144:262144
-v /opt/clickhouse/log:/var/log/clickhouse-server
-v /opt/clickhouse/data:/var/lib/clickhouse
yandex/clickhouse-server
次ã®ããã«ããŒã¿ããŒã¹ãšãã®äžã«ããŒãã«ãäœæããŸããã
CREATE TABLE
db.steps (`area` Int64, `when` DateTime64(1, 'Europe/Moscow') DEFAULT now64(), `zone` Int64, `person` Int64)
ENGINE = MergeTree() ORDER BY (area, zone, person) SETTINGS index_granularity = 8192
次ã®ã¹ã¯ãªããã䜿çšããŠããŒã¿ãå ¥åããŸããã
from time import time
from clickhouse_driver import Client
from random import random
client = Client('vm-12c2c34c-df68-4a98-b1e5-a4d1cef1acff.domain',
database='db',
password='secret')
max = 20
for r in range(0, 100000):
if r % 1000 == 0:
print("CNT: {}, TS: {}".format(r, time()))
data = [{
'area': 0,
'zone': 0,
'person': r
}]
while True:
if random() < 0.3:
break
data.append({
'area': 0,
'zone': int(random() * (max - 2)) + 1,
'person': r
})
data.append({
'area': 0,
'zone': max - 1,
'person': r
})
client.execute(
'INSERT INTO steps (area, zone, person) VALUES',
data
)
æ¿å ¥ã¯ãããã§è¡ããããããå ¥å㯠JanusGraph ãããã¯ããã«é«éã§ããã
JOIN ã䜿çšã㊠XNUMX ã€ã®ã¯ãšãªãäœæããŸããã ãã€ã³ã A ãããã€ã³ã B ã«ç§»åããã«ã¯:
SELECT s1.person AS person,
s1.zone,
s1.when,
s2.zone,
s2.when
FROM
(SELECT *
FROM steps
WHERE (area = 0)
AND (zone = 0)) AS s1 ANY INNER JOIN
(SELECT *
FROM steps AS s2
WHERE (area = 0)
AND (zone = 19)) AS s2 USING person
WHERE s1.when <= s2.when
3 ã€ã®ãã€ã³ãã確èªããã«ã¯:
SELECT s3.person,
s1z,
s1w,
s2z,
s2w,
s3.zone,
s3.when
FROM
(SELECT s1.person AS person,
s1.zone AS s1z,
s1.when AS s1w,
s2.zone AS s2z,
s2.when AS s2w
FROM
(SELECT *
FROM steps
WHERE (area = 0)
AND (zone = 0)) AS s1 ANY INNER JOIN
(SELECT *
FROM steps AS s2
WHERE (area = 0)
AND (zone = 3)) AS s2 USING person
WHERE s1.when <= s2.when) p ANY INNER JOIN
(SELECT *
FROM steps
WHERE (area = 0)
AND (zone = 19)) AS s3 USING person
WHERE p.s2w <= s3.when
ãã¡ããããã®ãªã¯ãšã¹ãã¯éåžžã«æããããã®ã«èŠããŸãããå®éã«äœ¿çšããã«ã¯ããœãããŠã§ã¢ ãžã§ãã¬ãŒã¿ãŒ ããŒãã¹ãäœæããå¿ èŠããããŸãã ãããã圌ãã¯ä»äºãããŠãããçŽ æ©ãä»äºãããŸãã æåãš 0.1 çªç®ã®ãªã¯ãšã¹ãã¯äž¡æ¹ãšã 3 ç§æªæºã§å®äºããŸãã 以äžã¯ãXNUMX ã€ã®ãã€ã³ããééãã count(*) ã®ã¯ãšãªå®è¡æéã®äŸã§ãã
SELECT count(*)
FROM
(
SELECT
s1.person AS person,
s1.zone AS s1z,
s1.when AS s1w,
s2.zone AS s2z,
s2.when AS s2w
FROM
(
SELECT *
FROM steps
WHERE (area = 0) AND (zone = 0)
) AS s1
ANY INNER JOIN
(
SELECT *
FROM steps AS s2
WHERE (area = 0) AND (zone = 3)
) AS s2 USING (person)
WHERE s1.when <= s2.when
) AS p
ANY INNER JOIN
(
SELECT *
FROM steps
WHERE (area = 0) AND (zone = 19)
) AS s3 USING (person)
WHERE p.s2w <= s3.when
ââcount()ââ
â 11592 â
âââââââââââ
1 rows in set. Elapsed: 0.068 sec. Processed 250.03 thousand rows, 8.00 MB (3.69 million rows/s., 117.98 MB/s.)
IOPS ã«é¢ãã泚æäºé ã ããŒã¿ãåã蟌ããšããJanusGraph ã¯ããªãé«ã IOPS (1000 ã€ã®ããŒã¿åã蟌ã¿ã¹ã¬ãã㧠1300 ïœ XNUMX) ãçæããIOWAIT ã¯ããªãé«ãã£ãã åæã«ãClickHouse ã¯ãã£ã¹ã¯ ãµãã·ã¹ãã ã«æå°éã®è² è·ãçæããŸããã
ãŸãšã
ãã®ã¿ã€ãã®ãªã¯ãšã¹ãã«ã¯ ClickHouse ã䜿çšããããšã«ããŸããã ClickHouse ã«ããŒãããåã« Apache Flink ã䜿çšããŠã€ãã³ã ã¹ããªãŒã ãååŠçããããšã§ããããªã¢ã©ã€ãºã ãã¥ãŒãšäžŠååã䜿çšããŠã¯ãšãªãããã«æé©åããããšãã§ããŸãã
ããã©ãŒãã³ã¹ãéåžžã«åªããŠãããããããã°ã©ã ã«ããããŒãã«ã®ããããã«ã€ããŠèããå¿ èŠãããªããªãã§ãããã 以åã¯ãApache Parquet ãžã®ã¢ããããŒããä»ã㊠Vertica ããååŸããããŒã¿ã®ãããããè¡ãå¿ èŠããããŸããã
æ®å¿µãªãããã°ã©ã DBMS ã䜿çšããå¥ã®è©Šã¿ã¯å€±æããŸããã JanusGraph ã«ã¯ããã®è£œåãç°¡åã«ç解ã§ãããã¬ã³ããªãŒãªãšã³ã·ã¹ãã ããããšã¯æããŸããã§ããã åæã«ããµãŒããŒã®èšå®ã«ã¯åŸæ¥ã® Java ã®æ¹æ³ã䜿çšããããããJava ã«è©³ãããªã人ã¯è¡ã®æ¶ãæµãããšã«ãªããŸãã
host: 0.0.0.0
port: 8182
threadPoolWorker: 1
gremlinPool: 8
scriptEvaluationTimeout: 30000
channelizer: org.janusgraph.channelizers.JanusGraphWsAndHttpChannelizer
graphManager: org.janusgraph.graphdb.management.JanusGraphManager
graphs: {
ConfigurationManagementGraph: conf/janusgraph-cql-configurationgraph.properties,
airlines: conf/airlines.properties
}
scriptEngines: {
gremlin-groovy: {
plugins: { org.janusgraph.graphdb.tinkerpop.plugin.JanusGraphGremlinPlugin: {},
org.apache.tinkerpop.gremlin.server.jsr223.GremlinServerGremlinPlugin: {},
org.apache.tinkerpop.gremlin.tinkergraph.jsr223.TinkerGraphGremlinPlugin: {},
org.apache.tinkerpop.gremlin.jsr223.ImportGremlinPlugin: {classImports: [java.lang.Math], methodImports: [java.lang.Math#*]},
org.apache.tinkerpop.gremlin.jsr223.ScriptFileGremlinPlugin: {files: [scripts/airline-sample.groovy]}}}}
serializers:
# GraphBinary is here to replace Gryo and Graphson
- { className: org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1, config: { ioRegistries: [org.janusgraph.graphdb.tinkerpop.JanusGraphIoRegistry] }}
- { className: org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1, config: { serializeResultToString: true }}
# Gryo and Graphson, latest versions
- { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { ioRegistries: [org.janusgraph.graphdb.tinkerpop.JanusGraphIoRegistry] }}
- { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { serializeResultToString: true }}
- { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV3d0, config: { ioRegistries: [org.janusgraph.graphdb.tinkerpop.JanusGraphIoRegistry] }}
# Older serialization versions for backwards compatibility:
- { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0, config: { ioRegistries: [org.janusgraph.graphdb.tinkerpop.JanusGraphIoRegistry] }}
- { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0, config: { serializeResultToString: true }}
- { className: org.apache.tinkerpop.gremlin.driver.ser.GryoLiteMessageSerializerV1d0, config: {ioRegistries: [org.janusgraph.graphdb.tinkerpop.JanusGraphIoRegistry] }}
- { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV2d0, config: { ioRegistries: [org.janusgraph.graphdb.tinkerpop.JanusGraphIoRegistry] }}
- { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV1d0, config: { ioRegistries: [org.janusgraph.graphdb.tinkerpop.JanusGraphIoRegistryV1d0] }}
- { className: org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV1d0, config: { ioRegistries: [org.janusgraph.graphdb.tinkerpop.JanusGraphIoRegistryV1d0] }}
processors:
- { className: org.apache.tinkerpop.gremlin.server.op.session.SessionOpProcessor, config: { sessionTimeout: 28800000 }}
- { className: org.apache.tinkerpop.gremlin.server.op.traversal.TraversalOpProcessor, config: { cacheExpirationTime: 600000, cacheMaxSize: 1000 }}
metrics: {
consoleReporter: {enabled: false, interval: 180000},
csvReporter: {enabled: false, interval: 180000, fileName: /tmp/gremlin-server-metrics.csv},
jmxReporter: {enabled: false},
slf4jReporter: {enabled: true, interval: 180000},
gangliaReporter: {enabled: false, interval: 180000, addressingMode: MULTICAST},
graphiteReporter: {enabled: false, interval: 180000}}
threadPoolBoss: 1
maxInitialLineLength: 4096
maxHeaderSize: 8192
maxChunkSize: 8192
maxContentLength: 65536
maxAccumulationBufferComponents: 1024
resultIterationBatchSize: 64
writeBufferHighWaterMark: 32768
writeBufferHighWaterMark: 65536
ssl: {
enabled: false}
ç§ã¯èª€ã£ãŠ JanusGraph ã® BerkeleyDB ããŒãžã§ã³ãã眮ããããšã«æåããŸããã
ã€ã³ããã¯ã¹ã管çããã«ã¯ãGroovy ã§ããªãå¥åŠãªã·ã£ãŒãããºã ãå®è¡ããå¿ èŠããããããããã¥ã¡ã³ãã¯ã€ã³ããã¯ã¹ã«é¢ããŠããªãæªãã§ããŸãã ããšãã°ãã€ã³ããã¯ã¹ã®äœæã¯ãGremlin ã³ã³ãœãŒã«ã§ã³ãŒããèšè¿°ããŠè¡ãå¿ èŠããããŸã (ã¡ãªã¿ã«ãããã¯ãã®ãŸãŸã§ã¯æ©èœããŸãã)ã JanusGraph ã®å ¬åŒããã¥ã¡ã³ããã:
graph.tx().rollback() //Never create new indexes while a transaction is active
mgmt = graph.openManagement()
name = mgmt.getPropertyKey('name')
age = mgmt.getPropertyKey('age')
mgmt.buildIndex('byNameComposite', Vertex.class).addKey(name).buildCompositeIndex()
mgmt.buildIndex('byNameAndAgeComposite', Vertex.class).addKey(name).addKey(age).buildCompositeIndex()
mgmt.commit()
//Wait for the index to become available
ManagementSystem.awaitGraphIndexStatus(graph, 'byNameComposite').call()
ManagementSystem.awaitGraphIndexStatus(graph, 'byNameAndAgeComposite').call()
//Reindex the existing data
mgmt = graph.openManagement()
mgmt.updateIndex(mgmt.getGraphIndex("byNameComposite"), SchemaAction.REINDEX).get()
mgmt.updateIndex(mgmt.getGraphIndex("byNameAndAgeComposite"), SchemaAction.REINDEX).get()
mgmt.commit()
åŸæžã
ããæå³ãäžèšã®å®éšã¯æž©ãããã®ãšæããããã®ã®æ¯èŒã§ãã èããŠã¿ããšãã°ã©ã DBMS ã¯åãçµæãåŸãããã«ä»ã®æäœãå®è¡ããŸãã ãã ãããã¹ãã®äžç°ãšããŠã次ã®ãããªãªã¯ãšã¹ãã䌎ãå®éšãå®æœããŸããã
g.V().hasLabel('ZoneStep').has('id',0)
.repeat(__.out().simplePath()).until(__.hasLabel('ZoneStep').has('id',1)).count().next()
æ©è¡è·é¢ãåæ ããŸãã ãããããã®ãããªããŒã¿ã§ãã£ãŠããã°ã©ã DBMS ã¯æ°ç§ãè¶
ããçµæã衚瀺ããŸãã...ããã¯ããã¡ããã次ã®ãããªãã¹ããã£ããšããäºå®ã«ãããã®ã§ãã 0 -> X -> Y ... -> 1
ãã°ã©ããšã³ãžã³ããã§ãã¯ããŸããã
次ã®ãããªã¯ãšãªã®å Žåã§ãã
g.V().hasLabel('ZoneStep').has('id',0).out().has('id',1)).count().next()
XNUMX ç§æªæºã®åŠçæéã§ã¯çç£çãªå¿çãåŸãããšãã§ããŸããã§ããã
ãã®è©±ã®æèšã¯ãçŸããã¢ã€ãã¢ãæš¡ç¯çãªã¢ããªã³ã°ãæãŸããçµæããããããªããšããããšã§ããããã¯ãClickHouse ã®äŸã䜿çšããŠã¯ããã«é«ãå¹çã§å®èšŒãããŠããŸãã ãã®èšäºã§çŽ¹ä»ãããŠãã䜿çšäŸã¯ãã°ã©ã DBMS ã®æããã«ã¢ã³ããã¿ãŒã³ã§ããããã®ãã©ãã€ã ã§ã®ã¢ããªã³ã°ã«ã¯é©ããŠããããã«èŠããŸãã
åºæïŒ habr.com