Статьи

Сайфер против Гремлин в Neo4j

Neo4jClient теперь поддерживает Cypher в качестве языка запросов с Neo4j. Однако я заметил следующее:

  • Простые обходы графа намного эффективнее при использовании Gremlin
  • Запросы в Гремлин на 30-50% быстрее для простых прохождений
  • Cypher идеально подходит для сложных обходов, где требуется обратное отслеживание
  • Cypher — наш выбор языка запросов для отчетов.
  • Gremlin — наш выбор языка запросов для простых прохождений, где проекции не требуются
  • Cypher имеет встроенную модель проекции таблицы, где модель проекции таблицы Gremlins опирается на шаги AS, которые могут быть громоздкими при возврате, например, Back (), As () и _CopySplit , где cypher — просто совпадения, разделенные запятыми.
  • Cypher гораздо лучше подходит для внешних объединений, чем Gremlin, для достижения аналогичных результатов в gremlin требуются параллельные запросы с CopySplit, где, как и в Cypher, используется предложение Match с необязательными отношениями.
  • Gremlin идеально подходит для получения очень простых структур данных.
  • Проекция таблицы в гремлине может быть очень мощной, однако внешние объединения могут быть очень многословными

Короче говоря, нам нравится использовать Cypher, когда нам нужны табличные данные из Neo4j, и это особенно полезно при внешних соединениях.

Вот два запроса, которые возвращают те же самые данные из Neo4j, один в Cypher и один в Gremlin.

Cypher Report Query

var resultSet = graphClient.RootNode
                .StartCypher("root")
                .Match(@"root-[:HOSTS]->(agency)
                       <-[:USER_BELONGS_TO]-(user)-[:USER_LINKED_TO_PROGRAM]
                       ->(program)
                       <-[:HAS_PROGRAM]-(centre),
                       (program)<-[:HAS_SUGGESTED_PROGRAM]-(referralDecisionsSection)
                       <-[:REFERRAL_HAS_DECISIONS_SECTION]-(referral)-[:CREATED_BY]
                       ->(createdByUser), (referral)-[:REFERRAL_HAS_WHO_SECTION]
                       ->(whoSection)-[:HAS_PARTICIPANT]->(participant)")
                .Where<Agency>(agency => agency.Key == userIdentifier.AgencyKey)
                .And()
                .Where<User>(user => user.Username == userIdentifier.Username)
                .And()
                .Where<Referral>(referral => referral.Completed == false)
                .Return((user, program, centre, createdByUser, referral, whoSection, participant) => 
                new ReferralByGroup
                {
                    UserFamilyName = createdByUser.As<User>().FamilyName,
                    UserGivenName = createdByUser.As<User>().GivenName,
                    Program = program.As<Program>().Name,
                    Centre = centre.As<Centre>().Name,
                    ReferralId = referral.As<Referral>().UniqueId,
                    ReferralDate = whoSection.As<ReferralWhoSection>().ReferralDate,
                    ParticipantName = participant.As<ReferralParticipant>().Name,
                    ParticipantDisplayOrder = participant.As<ReferralParticipant>().DisplayOrder,
                })
                .Results
                .ToArray();

Запрос отчетов Gremlin с использованием табличных проекций

var resultSet = graphClient
    .RootNode
    .Out<Agency>(Hosts.TypeKey, a => a.Key == userIdentifier.AgencyKey)
    .In<User>(UserBelongsTo.TypeKey, u => u.Username == userIdentifier.Username)
    .Out<Program>(UserLinkedToProgram.TypeKey)
    .As("Program")
    .In<Centre>(HasProgram.TypeKey)
    .As("Centre")
    .BackV<Program>("Program")
    .In<ReferralDecisionsSection>(HasSuggestedProgram.TypeKey)
    .In<Referral>(ReferralHasDecisionsSection.TypeKey, r => r.Completed == false)
    .As("ReferralId")
    .Out<User>(CreatedBy.TypeKey)
    .As("UserGivenName")
    .As("UserFamilyName")
    .BackV<Referral>("ReferralId")
    .Out<ReferralWhoSection>(ReferralHasWhoSection.TypeKey)
    .As("ReferralDate")
    .Out<ReferralParticipant>(HasParticipant.TypeKey)
    .As("ParticipantDisplayOrder")
    .As("ParticipantName")
    .Table
    <ReferralByGroup, Program, Centre, Referral, User, User, ReferralWhoSection, ReferralParticipant,
        ReferralParticipant>(
            program => program.Name,
            centre => centre.Name,
            referral => referral.UniqueId,
            user => user.FamilyName,
            user => user.GivenName,
            who => who.ReferralDate,
            participant => participant.Name,
            participant => participant.DisplayOrder
    )
    .ToArray();

 Below is the converted parameterised script sent for cypher and gremlin respectively for those not familiar with the Neo4jClient.

Cypher

START root=node({p8})
MATCH root-[:HOSTS]->(agency)
                       <-[:USER_BELONGS_TO]-(user)-[:USER_LINKED_TO_PROGRAM]->(program)
                       <-[:HAS_PROGRAM]-(centre),
                       (program)<-[:HAS_SUGGESTED_PROGRAM]-(referralDecisionsSection)
                       <-[:REFERRAL_HAS_DECISIONS_SECTION]-(referral)-[:CREATED_BY]
                       ->(createdByUser), (referral)-[:REFERRAL_HAS_WHO_SECTION]
                       ->(whoSection)-[:HAS_PARTICIPANT]
                       ->(participant)
WHERE (agency.Key? = {p0}) AND (user.Username? = {p1}) AND (referral.Completed? = {p2})
RETURN createdByUser.FamilyName? AS UserFamilyName, createdByUser.GivenName? AS UserGivenName, program.Name? AS Program, centre.Name? AS Centre, referral.UniqueId? AS ReferralId, whoSection.ReferralDate? AS ReferralDate, participant.Name? AS ParticipantName, participant.DisplayOrder? AS ParticipantDisplayOrder

 

Gremlin

g.v(p0)
.out(p1).filter{ it[p2].equalsIgnoreCase(p3) }
.in(p4).filter{ it[p5].equalsIgnoreCase(p6) }
.out(p7).as(p8).in(p9).as(p10).back(p11)
.in(p12).in(p13).filter{ it[p14] == p15 }.as(p16)
.out(p17).as(p18).as(p19).back(p20)
.out(p21).as(p22).out(p23).as(p24).as(p25)
.table(new Table()){it[p26]}{it[p27]}{it[p28]}{it[p29]}{it[p30]}{it[p31]}{it[p32]}{it[p33]}
.cap

 I have included below the non-paramerterised cypher and gremlin query respectively.

Cypher

START root=node(0)
MATCH root-[:HOSTS]->(agency)<-[:USER_BELONGS_TO]-(user)-[:USER_LINKED_TO_PROGRAM]
->(program)
<-[:HAS_PROGRAM]-(centre),(program)
<-[:HAS_SUGGESTED_PROGRAM]-(referralDecisionsSection)
<-[:REFERRAL_HAS_DECISIONS_SECTION]-(referral)-[:CREATED_BY]->(createdByUser), (referral)-[:REFERRAL_HAS_WHO_SECTION]
->(whoSection)-[:HAS_PARTICIPANT]
->(participant)   WHERE (agency.Key? = romikoagency) AND (user.Username? = romiko.derbynew) AND (referral.Completed? = false)   
RETURN createdByUser.FamilyName? AS UserFamilyName, createdByUser.GivenName? AS UserGivenName, program.Name? AS Program, centre.Name? AS Centre, referral.UniqueId? AS ReferralId, whoSection.ReferralDate? AS ReferralDate, participant.Name? AS ParticipantName, participant.DisplayOrder? AS ParticipantDisplayOrder

 

Gremlin

g.v('0').out('HOSTS').filter{ it['Key'].equalsIgnoreCase('romikoagency') }
.in('USER_BELONGS_TO').filter{ it['Username'].equalsIgnoreCase('romiko.derbynew') }
.out('USER_LINKED_TO_PROGRAM').as('Program')
.in('HAS_PROGRAM').as('Centre').back('Program')
.in('HAS_SUGGESTED_PROGRAM')
.in('REFERRAL_HAS_DECISIONS_SECTION').filter{ it['Completed'] == false }.as('ReferralId')
.out('CREATED_BY').as('UserGivenName').as('UserFamilyName').back('ReferralId')
.out('REFERRAL_HAS_WHO_SECTION').as('ReferralDate')
.out('HAS_PARTICIPANT').as('ParticipantDisplayOrder').as('ParticipantName')
.table(new Table()){it['Name']}{it['Name']}{it['UniqueId']}{it['FamilyName']}{it['GivenName']}{it['ReferralDate']}{it['Name']}{it['DisplayOrder']}.cap