తగిన మార్గాలను కనుగొనడంలో సమస్యను పరిష్కరించడానికి JanusGraph గ్రాఫ్ DBMS యొక్క అనువర్తనాన్ని పరీక్షించే ప్రయోగం

తగిన మార్గాలను కనుగొనడంలో సమస్యను పరిష్కరించడానికి JanusGraph గ్రాఫ్ DBMS యొక్క అనువర్తనాన్ని పరీక్షించే ప్రయోగం

అందరికి వందనాలు. మేము ఆఫ్‌లైన్ ట్రాఫిక్ విశ్లేషణ కోసం ఒక ఉత్పత్తిని అభివృద్ధి చేస్తున్నాము. ప్రాజెక్ట్‌కి ప్రాంతాలలో సందర్శకుల మార్గాల గణాంక విశ్లేషణకు సంబంధించిన పని ఉంది.

ఈ టాస్క్‌లో భాగంగా, వినియోగదారులు కింది రకానికి చెందిన సిస్టమ్ ప్రశ్నలను అడగవచ్చు:

  • "A" ప్రాంతం నుండి "B" ప్రాంతానికి ఎంత మంది సందర్శకులు వచ్చారు;
  • "A" ప్రాంతం నుండి "B" ప్రాంతం "C" ద్వారా మరియు ఆ తర్వాత "D" ప్రాంతం ద్వారా ఎంతమంది సందర్శకులు వెళ్లారు;
  • "A" ప్రాంతం నుండి "B" ప్రాంతానికి ప్రయాణించడానికి నిర్దిష్ట రకం సందర్శకులకు ఎంత సమయం పట్టింది.

మరియు ఇలాంటి అనేక విశ్లేషణాత్మక ప్రశ్నలు.

ప్రాంతాలలో సందర్శకుల కదలిక నిర్దేశిత గ్రాఫ్. ఇంటర్నెట్ చదివిన తర్వాత, గ్రాఫ్ DBMSలు విశ్లేషణాత్మక నివేదికల కోసం కూడా ఉపయోగించబడుతున్నాయని నేను కనుగొన్నాను. అటువంటి ప్రశ్నలను గ్రాఫ్ DBMSలు ఎలా ఎదుర్కోవాలో చూడాలనే కోరిక నాకు ఉంది (TL; DR; పేలవంగా).

నేను DBMSని ఉపయోగించాలని ఎంచుకున్నాను జానస్ గ్రాఫ్, గ్రాఫ్ ఓపెన్-సోర్స్ DBMS యొక్క అత్యుత్తమ ప్రతినిధిగా, ఇది పరిణతి చెందిన సాంకేతికతల స్టాక్‌పై ఆధారపడుతుంది, ఇది (నా అభిప్రాయం ప్రకారం) తగిన కార్యాచరణ లక్షణాలను అందించాలి:

  • BerkeleyDB నిల్వ బ్యాకెండ్, Apache Cassandra, Scylla;
  • సంక్లిష్ట సూచికలను Lucene, Elasticsearch, Solrలో నిల్వ చేయవచ్చు.

JanusGraph రచయితలు ఇది OLTP మరియు OLAP రెండింటికీ సరిపోతుందని వ్రాశారు.

నేను BerkeleyDB, Apache Cassandra, Scylla మరియు ESతో పని చేసాను మరియు ఈ ఉత్పత్తులు మా సిస్టమ్‌లలో తరచుగా ఉపయోగించబడుతున్నాయి, కాబట్టి నేను ఈ గ్రాఫ్ DBMSని పరీక్షించడం పట్ల ఆశాజనకంగా ఉన్నాను. RocksDB కంటే BerkeleyDBని ఎంచుకోవడం నాకు అసహజంగా అనిపించింది, కానీ అది లావాదేవీ అవసరాల వల్ల కావచ్చు. ఏదైనా సందర్భంలో, స్కేలబుల్, ఉత్పత్తి ఉపయోగం కోసం, కాసాండ్రా లేదా స్కిల్లాపై బ్యాకెండ్‌ని ఉపయోగించమని సూచించబడింది.

నేను Neo4jని పరిగణించలేదు ఎందుకంటే క్లస్టరింగ్‌కి వాణిజ్య సంస్కరణ అవసరం, అంటే ఉత్పత్తి తెరవబడలేదు.

గ్రాఫ్ DBMSలు ఇలా చెబుతున్నాయి: "ఇది గ్రాఫ్ లాగా ఉంటే, దానిని గ్రాఫ్ లాగా పరిగణించండి!" - అందం!

మొదట, నేను గ్రాఫ్‌ను గీసాను, ఇది గ్రాఫ్ DBMSల నిబంధనల ప్రకారం ఖచ్చితంగా రూపొందించబడింది:

తగిన మార్గాలను కనుగొనడంలో సమస్యను పరిష్కరించడానికి JanusGraph గ్రాఫ్ 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), మీరు జోన్‌కు అంచు ఉన్న జోన్‌స్టెప్‌లను కనుగొనే వరకు వెనక్కి వెళ్లకుండా స్టాంప్ చేయండి ID=19, అటువంటి గొలుసుల సంఖ్యను లెక్కించండి.

గ్రాఫ్‌లపై శోధించడంలో ఉన్న చిక్కులన్నీ నాకు తెలిసినట్లు నటించడం లేదు, కానీ ఈ ప్రశ్న ఈ పుస్తకం ఆధారంగా రూపొందించబడింది (https://kelvinlawrence.net/book/Gremlin-Graph-Guide.html).

నేను BerkeleyDB బ్యాకెండ్‌ని ఉపయోగించి 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)

మేము SSDలో 4 కోర్లు మరియు 16 GB RAMతో VMని ఉపయోగించాము. JanusGraph ఈ ఆదేశాన్ని ఉపయోగించి అమలు చేయబడింది:

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

ఈ సందర్భంలో, ఖచ్చితమైన మ్యాచ్ శోధనల కోసం ఉపయోగించే డేటా మరియు సూచికలు BerkeleyDBలో నిల్వ చేయబడతాయి. ఇంతకు ముందు ఇచ్చిన అభ్యర్థనను అమలు చేసిన తర్వాత, నేను అనేక పదుల సెకన్లకు సమానమైన సమయాన్ని అందుకున్నాను.

ఎగువన ఉన్న 4 స్క్రిప్ట్‌లను సమాంతరంగా అమలు చేయడం ద్వారా, డాకర్ లాగ్‌లలో జావా స్టాక్‌ట్రేస్‌ల (మరియు మనమందరం జావా స్టాక్‌ట్రేస్‌లను చదవడానికి ఇష్టపడతాము) ఆనందకరమైన స్ట్రీమ్‌తో DBMSని గుమ్మడికాయగా మార్చగలిగాను.

కొంత ఆలోచన తర్వాత, నేను గ్రాఫ్ రేఖాచిత్రాన్ని క్రింది విధంగా సరళీకృతం చేయాలని నిర్ణయించుకున్నాను:

తగిన మార్గాలను కనుగొనడంలో సమస్యను పరిష్కరించడానికి JanusGraph గ్రాఫ్ 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ని కనుగొనే వరకు వెనక్కి వెళ్లకుండా స్టాంప్ చేయండి, అటువంటి గొలుసుల సంఖ్యను లెక్కించండి.

అనవసరమైన కనెక్షన్‌లను సృష్టించకుండా, లక్షణాలకు నన్ను పరిమితం చేయకుండా నేను పైన ఇచ్చిన లోడింగ్ స్క్రిప్ట్‌ను కూడా సరళీకృతం చేసాను.

అభ్యర్థన పూర్తి కావడానికి ఇంకా చాలా సెకన్ల సమయం పట్టింది, ఇది మా పనికి పూర్తిగా ఆమోదయోగ్యం కాదు, ఎందుకంటే ఇది ఏ రకమైన AdHoc అభ్యర్థనల ప్రయోజనాలకు కూడా తగినది కాదు.

నేను జానస్‌గ్రాఫ్‌ని వేగవంతమైన కాసాండ్రా ఇంప్లిమెంటేషన్‌గా స్కిల్లాను ఉపయోగించి అమలు చేయడానికి ప్రయత్నించాను, కానీ ఇది కూడా ఎటువంటి ముఖ్యమైన పనితీరు మార్పులకు దారితీయలేదు.

కాబట్టి "ఇది గ్రాఫ్ లాగా ఉంది" అయినప్పటికీ, దాన్ని త్వరగా ప్రాసెస్ చేయడానికి నేను గ్రాఫ్ DBMSని పొందలేకపోయాను. నాకు తెలియనిది ఏదైనా ఉందని మరియు ఈ శోధనను సెకనులో కొంత భాగానికి జానస్‌గ్రాఫ్ చేయవచ్చని నేను పూర్తిగా ఊహిస్తున్నాను, అయినప్పటికీ, నేను దీన్ని చేయలేకపోయాను.

సమస్య ఇంకా పరిష్కరించాల్సిన అవసరం ఉన్నందున, నేను JOINలు మరియు పట్టికల పైవట్‌ల గురించి ఆలోచించడం ప్రారంభించాను, ఇది చక్కదనం పరంగా ఆశావాదాన్ని ప్రేరేపించలేదు, కానీ ఆచరణలో పూర్తిగా పని చేయగల ఎంపిక.

మా ప్రాజెక్ట్ ఇప్పటికే Apache ClickHouseని ఉపయోగిస్తోంది, కాబట్టి నేను ఈ విశ్లేషణాత్మక DBMSపై నా పరిశోధనను పరీక్షించాలని నిర్ణయించుకున్నాను.

సరళమైన వంటకాన్ని ఉపయోగించి క్లిక్‌హౌస్‌ని అమలు చేసారు:

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
    )

ఇన్‌సర్ట్‌లు బ్యాచ్‌లలో వస్తాయి కాబట్టి, జానస్‌గ్రాఫ్ కంటే ఫిల్లింగ్ చాలా వేగంగా జరిగింది.

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 డిస్క్ సబ్‌సిస్టమ్‌పై కనీస లోడ్‌ను రూపొందించింది.

తీర్మానం

మేము ఈ రకమైన అభ్యర్థనను అందించడానికి క్లిక్‌హౌస్‌ని ఉపయోగించాలని నిర్ణయించుకున్నాము. క్లిక్‌హౌస్‌లోకి లోడ్ చేయడానికి ముందు Apache Flinkని ఉపయోగించి ఈవెంట్ స్ట్రీమ్‌ను ప్రీ-ప్రాసెస్ చేయడం ద్వారా మెటీరియలైజ్డ్ వీక్షణలు మరియు సమాంతరీకరణను ఉపయోగించి ప్రశ్నలను మేము ఎల్లప్పుడూ మరింత ఆప్టిమైజ్ చేయవచ్చు.

పనితీరు చాలా బాగుంది కాబట్టి మేము బహుశా ప్రోగ్రామ్‌ల ప్రకారం పట్టికలను పివోట్ చేయడం గురించి ఆలోచించాల్సిన అవసరం లేదు. ఇంతకుముందు, మేము వెర్టికా నుండి అపాచీ పార్కెట్‌కి అప్‌లోడ్ చేయడం ద్వారా తిరిగి పొందిన డేటా యొక్క పైవట్‌లను చేయాల్సి ఉంటుంది.

దురదృష్టవశాత్తూ, గ్రాఫ్ 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 యొక్క BerkeleyDB వెర్షన్‌ను "పుట్" చేయగలిగాను.

ఇండెక్స్‌ల పరంగా డాక్యుమెంటేషన్ చాలా వంకరగా ఉంది, ఎందుకంటే ఇండెక్స్‌లను నిర్వహించడానికి మీరు గ్రూవీలో కొన్ని విచిత్రమైన షమానిజం ప్రదర్శించాల్సి ఉంటుంది. ఉదాహరణకు, గ్రెమ్లిన్ కన్సోల్‌లో కోడ్ రాయడం ద్వారా ఇండెక్స్‌ను సృష్టించడం తప్పనిసరిగా చేయాలి (ఇది బాక్స్ వెలుపల పని చేయదు). అధికారిక 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()

నేను సెకను కంటే తక్కువ ప్రాసెసింగ్ సమయంతో ఉత్పాదక ప్రతిస్పందనను పొందలేకపోయాను.

కథ యొక్క నైతికత ఏమిటంటే, ఒక అందమైన ఆలోచన మరియు పారాడిగ్మాటిక్ మోడలింగ్ ఆశించిన ఫలితానికి దారితీయవు, ఇది క్లిక్‌హౌస్ ఉదాహరణను ఉపయోగించి చాలా ఎక్కువ సామర్థ్యంతో ప్రదర్శించబడుతుంది. ఈ ఆర్టికల్‌లో అందించబడిన వినియోగ సందర్భం గ్రాఫ్ DBMSల కోసం స్పష్టమైన వ్యతిరేక నమూనా, అయినప్పటికీ ఇది వాటి నమూనాలో మోడలింగ్‌కు అనుకూలంగా ఉన్నట్లు అనిపిస్తుంది.

మూలం: www.habr.com

ఒక వ్యాఖ్యను జోడించండి