ተስማሚ መንገዶችን የማግኘት ችግርን ለመፍታት የ JanusGraph ግራፍ ዲቢኤምኤስ ተፈጻሚነት ለመፈተሽ የተደረገ ሙከራ

ተስማሚ መንገዶችን የማግኘት ችግርን ለመፍታት የ JanusGraph ግራፍ ዲቢኤምኤስ ተፈጻሚነት ለመፈተሽ የተደረገ ሙከራ

ሰላም ሁላችሁም። ከመስመር ውጭ ትራፊክ ትንተና የሚሆን ምርት እያዘጋጀን ነው። ፕሮጀክቱ በክልል የጎብኝዎች እንቅስቃሴ መንገዶችን ከስታቲስቲክስ ትንተና ጋር የተያያዘ ተግባር አለው።

እንደ የዚህ ተግባር አካል ተጠቃሚዎች የስርዓት ጥያቄዎችን በሚከተለው ቅጽ መጠየቅ ይችላሉ።

  • ከ "A" አካባቢ ወደ "ቢ" አካባቢ ምን ያህል ጎብኚዎች አለፉ;
  • ስንት ጎብኝዎች ከ "ሀ" ወደ አካባቢ "ለ" በ "ሐ" እና ከዚያም በ "ዲ" አካባቢ አለፉ;
  • አንድ የተለየ ጎብኚ ከአካባቢ "ሀ" ወደ "ቢ" ለመጓዝ ምን ያህል ጊዜ ፈጅቷል.

እና በርካታ ተመሳሳይ የትንታኔ መጠይቆች።

በክልሎች በኩል የጎብኝው እንቅስቃሴ የሚመራ ግራፍ ነው። ኢንተርኔት ካነበብኩ በኋላ፣ DBMS ግራፍ ለትንታኔ ዘገባዎችም ጥቅም ላይ እንደሚውል ተረድቻለሁ። ግራፍ ዲቢኤምኤስ እንዴት እንደዚህ አይነት ጥያቄዎችን እንደሚቋቋም ለማየት ፍላጎት ነበረኝ (TL; DR; ደካማ)።

DBMS ለመጠቀም መርጫለሁ። ጃነስ ግራፍእንደ ምርጥ የግራፍ ክፍት ምንጭ ዲቢኤምኤስ ተወካይ (በእኔ አስተያየት) ጥሩ የአሠራር ባህሪዎችን ሊሰጡት በሚገቡ የበሰሉ ቴክኖሎጂዎች ላይ የሚመረኮዝ ነው።

  • የማከማቻ ጀርባ በርክሌይዲቢ፣ Apache Cassandra፣ Scylla;
  • ውስብስብ ኢንዴክሶች በ Lucene, Elasticsearch, Solr ውስጥ ሊቀመጡ ይችላሉ.

የ JanusGraph ደራሲዎች ለሁለቱም OLTP እና OLAP ተስማሚ እንደሆነ ይጽፋሉ።

ከበርክሌይዲቢ፣ Apache Cassandra፣ Scylla እና ES ጋር ሰርቻለሁ፣ እና እነዚህ ምርቶች በስርዓታችን ውስጥ ብዙ ጊዜ ጥቅም ላይ ይውላሉ፣ ስለዚህ ይህን ግራፍ DBMS ለመፈተሽ ብሩህ ተስፋ ነበረኝ። በርክሌይዲቢ በRoksDB ላይ መምረጥ እንግዳ ሆኖ አግኝቼዋለሁ፣ ግን ምናልባት ከግብይት መስፈርቶች ጋር የተያያዘ ሊሆን ይችላል። ለማንኛውም፣ ለሚለካው፣ ለምርት አጠቃቀም፣ ካሳንድራ ወይም Scylla backend ለመጠቀም ይመከራል።

Neo4jን ግምት ውስጥ አላስገባኝም, ምክንያቱም ስብስብ የንግድ ስሪት ያስፈልገዋል, ማለትም ምርቱ ክፍት አይደለም.

ግራፍ ዲቢኤምኤስ እንዲህ ይላል፡ "አንድ ነገር ግራፍ የሚመስል ከሆነ እንደ ግራፍ ይያዙት!" - ውበት!

በመጀመሪያ፣ በግራፍ ዲቢኤምኤስ ቀኖናዎች መሠረት የተሰራውን ግራፍ ሣልኩ፡-

ተስማሚ መንገዶችን የማግኘት ችግርን ለመፍታት የ JanusGraph ግራፍ ዲቢኤምኤስ ተፈጻሚነት ለመፈተሽ የተደረገ ሙከራ

ምንነት አለ። 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()

በሩሲያኛ እንደዚህ ያለ ነገር ነው-ዞን መታወቂያ = 0 ይፈልጉ ፣ ጠርዙ ወደ እሱ የሚሄድባቸውን ጫፎች ሁሉ ይውሰዱ (ZoneStep) ፣ እንደዚህ ያለ ZoneStep እስኪያገኙ ድረስ ተመልሰው ያዙሩ ፣ ከዚያ ጠርዙ መታወቂያ ያለው ወደ ዞን ይሄዳል =19, እንደዚህ አይነት ሰንሰለቶች ቁጥር ይቁጠሩ.

ሁሉንም የግራፍ ፍለጋ ውስብስብ ነገሮች እንዳውቅ አላስመሰልኩም፣ ነገር ግን ይህ ጥያቄ የተፈጠረው በዚህ መጽሐፍ ላይ ነው (https://kelvinlawrence.net/book/Gremlin-Graph-Guide.html).

ከ 50 እስከ 3 ነጥብ ርዝማኔ 20 ሺህ ትራኮችን ወደ JanusGraph ግራፍ ዳታቤዝ ሰቅዬ የቤርክሌይ ዲቢ ጀርባን በመጠቀም ኢንዴክሶችን በተፈጠሩ አመራር.

የፓይዘን አውርድ ስክሪፕት፡-


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)

ጥቅም ላይ የዋለው ቪኤም ከ4 ኮር እና 16 ጊባ ራም በኤስኤስዲ ላይ። JanusGraph የተሰማራው በሚከተለው ትዕዛዝ ነው፡-

docker run --name janusgraph -p8182:8182 janusgraph/janusgraph:latest

በዚህ አጋጣሚ ለትክክለኛ ግጥሚያ ፍለጋዎች ጥቅም ላይ የሚውሉ መረጃዎች እና ኢንዴክሶች በበርክሌይዲቢ ውስጥ ተከማችተዋል። ቀደም ሲል የተሰጠውን ጥያቄ ከፈጸምኩ በኋላ፣ ከበርካታ አስር ሰከንዶች ጋር እኩል የሆነ ጊዜ አግኝቻለሁ።

ከላይ ያሉትን 4 ስክሪፕቶች በትይዩ በማስኬድ ዲቢኤምኤስን ወደ ዱባነት ቀይሬው ደስ የሚል የጃቫ ቁልል ዱካዎች (እና ሁላችንም የጃቫ ቁልል ዱካዎችን ማንበብ እንወዳለን) በ Docker logs ውስጥ።

በማሰላሰል፣ የግራፉን ንድፍ ወደሚከተለው ለማቃለል ወሰንኩ፡-

ተስማሚ መንገዶችን የማግኘት ችግርን ለመፍታት የ JanusGraph ግራፍ ዲቢኤምኤስ ተፈጻሚነት ለመፈተሽ የተደረገ ሙከራ

የህጋዊ አካል መለያ ፍለጋዎች ከዳር እይታዎች የበለጠ ፈጣን እንደሚሆን መወሰን። በዚህ ምክንያት ጥያቄዬ ወደሚከተለው ተለወጠ።

g.V().hasLabel('ZoneStep').has('id',0).repeat(__.out().simplePath()).until(__.hasLabel('ZoneStep').has('id',19)).count().next()

በሩሲያኛ እንደዚህ ያለ ነገር ነው-ZoneStep በ ID = 0 ይፈልጉ ፣ ወደ ኋላ ሳይመለሱ መታወቂያ=19 ያለው ZoneStep እስኪያገኙ ድረስ ይራመዱ ፣ የእነዚህን ሰንሰለቶች ብዛት ይቁጠሩ።

እንዲሁም በባህሪያት የተገደቡ አላስፈላጊ አገናኞችን ላለመፍጠር ከላይ ያለውን የማውረጃ ስክሪፕት ቀለል አድርጌዋለሁ።

ጥያቄው አሁንም ለጥቂት ሰኮንዶች እየሄደ ነበር፣ ይህም ለኛ ተግባር ሙሉ በሙሉ ተቀባይነት የሌለው ነበር፣ ምክንያቱም ለአድሆክ የዘፈቀደ ዓይነት ጥያቄዎች ይህ በጭራሽ ተስማሚ ስላልሆነ።

JanusGraphን Scyllaን እንደ ካሳንድራ ፈጣኑ ትግበራ ለማሰማራት ሞከርኩ፣ ነገር ግን ያ ምንም አይነት የአፈጻጸም ልዩነት አላመጣም።

ስለዚህ "ግራፍ ቢመስልም" ግራፍ DBMS በፍጥነት እንዲሰራው ማድረግ አልቻልኩም። አንድ ነገር እንደማላውቅ እገምታለሁ እናም JanusGraph ይህንን ፍለጋ በሰከንድ ውስጥ እንዲሰራ ማድረግ ይቻላል ፣ ግን አልተሳካልኝም።

አሁንም ችግሩን መፍታት ስለሚያስፈልገኝ ስለ JOINs እና Pivot ሰንጠረዦች ማሰብ ጀመርኩ, ይህም በቅንጦት ረገድ ብሩህ ተስፋን አያነሳሳም, ነገር ግን በተግባር ግን በጣም ጥሩ አማራጭ ሊሆን ይችላል.

የእኛ ፕሮጀክት አስቀድሞ Apache ClickHouse ይጠቀማል፣ ስለዚህ በዚህ የትንታኔ ዲቢኤምኤስ ላይ ምርምሬን ለመሞከር ወሰንኩ።

በቀላል የምግብ አሰራር መሰረት የተከፈተ 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ን በመጠቀም ሁለት ጥያቄዎችን ነድፏል። ከ ነጥብ 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 ነጥብ ለማለፍ የጥያቄው ማስፈጸሚያ ጊዜ ምሳሌ ይኸውና፡

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 ለአራት የመረጃ ሙሌት ክሮች) አመነጨ እና IOWAIT በጣም ከፍተኛ ነበር። በተመሳሳይ ጊዜ, ClickHouse በዲስክ ንዑስ ስርዓት ላይ አነስተኛ ጭነት ፈጠረ.

መደምደሚያ

የዚህ አይነት ጥያቄዎችን ለማቅረብ ClickHouse ን ለመጠቀም ወስነናል። ወደ ClickHouse ከመጫንዎ በፊት የዝግጅቶችን ዥረት በApache Flink ቀድመን በማዘጋጀት ቁሳቁሳዊ እይታዎችን እና ትይዩዎችን በመጠቀም ሁልጊዜ መጠይቆችን ማሳደግ እንችላለን።

አፈፃፀሙ በጣም ጥሩ ከመሆኑ የተነሳ የጠረጴዛ ምሰሶዎችን በፕሮግራማዊ መንገድ እንኳን ማሰብ አይኖርብንም። ከዚህ ቀደም ወደ Apache Parquet በመስቀል ከVertica የተገኘ የውሂብ ምሰሶዎችን መስራት ነበረብን።

እንደ አለመታደል ሆኖ፣ ግራፍ DBMS ለመጠቀም የተደረገ ሌላ ሙከራ አልተሳካም። JanusGraph በምርቱ በፍጥነት እንዲመችዎ የሚያስችል ተስማሚ ምህዳር እንዳለው አላገኘሁም። በተመሳሳይ ጊዜ ባህላዊው የጃቫ-መንገድ አገልጋዩን ለማዋቀር ጥቅም ላይ ይውላል ፣ ይህም ከጃቫ ጋር የማይተዋወቁ ሰዎችን የደም እንባ ያነባል።

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 ሥሪት በድንገት "ማስቀመጥ" ቻልኩ።

ሰነዱ ከመረጃ ጠቋሚዎች አንፃር ጠማማ ነው ፣ ምክንያቱም ኢንዴክሶችን በሚያስተዳድሩበት ጊዜ በግሩቪ ላይ አንዳንድ ያልተለመደ ሻማኒዝም ማድረግ ያስፈልግዎታል። ለምሳሌ ኢንዴክስ መፍጠር በግሬምሊን ኮንሶል (በነገራችን ላይ ከሳጥኑ ውጭ የማይሰራ) ኮድ በመፃፍ መከናወን አለበት። ከ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()

የእግር ጉዞ ርቀትን የሚያንፀባርቅ. ሆኖም ፣ በእንደዚህ ዓይነት መረጃዎች ላይ እንኳን ፣ ግራፉ ዲቢኤምኤስ ከጥቂት ሰከንዶች በላይ የሄደ ውጤት አሳይቷል ... ይህ በእርግጥ ፣ የቅጹ መንገዶች በመኖራቸው ምክንያት ነው። 0 -> X -> Y ... -> 1, ይህም የግራፍ ሞተር እንዲሁ ፈትሸው.

ለእይታ ጥያቄ እንኳን፡-

g.V().hasLabel('ZoneStep').has('id',0).out().has('id',1)).count().next()

ከአንድ ሰከንድ ባነሰ ጊዜ የማቀናበር ውጤታማ ምላሽ ማግኘት አልቻልኩም።

የተረት ሥነ-ምግባር ቆንጆ ሀሳብ እና ምሳሌያዊ ሞዴሊንግ ወደሚፈለገው ውጤት አይመራም ፣ ይህም የ ClickHouse ምሳሌን በመጠቀም በጣም ከፍተኛ ብቃት ያሳያል። በዚህ ጽሑፍ ውስጥ የቀረበው የአጠቃቀም ጉዳይ ለግራፍ ዲቢኤምኤስ ግልጽ የሆነ ፀረ-ንድፍ ነው, ምንም እንኳን በአምሳያቸው ውስጥ ለመቅረጽ ተስማሚ ቢመስልም.

ምንጭ: hab.com

አስተያየት ያክሉ