Предложение о совпадении неразрешимо. Поведение не ясно - PullRequest
0 голосов
/ 20 мая 2019

Я собираю запросы программно во время выполнения, и предложение match является более общим способом решения этой задачи. Большинство из них работают нормально, но некоторые в какой-то момент возвращают исключение «Неразрешимый шаблон».

Я проверил здесь как единственный подобный вопрос на SO, но он не отвечает и не объясняет проблему, по крайней мере для меня.

Вот моя неудачная попытка.

g.V().match(
        __.as('loc').has('guid','EGLD').out('instanceOfSupClass').hasLabel('Main_Location'),
        __.as('meter1').out('instanceOfSupClass').hasLabel('Electricity_Meter'),
        __.as('meter2').out('instanceOfSupClass').hasLabel('Electricity_Meter'),
        __.as('class').out('instanceOfSupClass').hasLabel('Cleaned_Electricty_Meter'),
        __.as('meter1').out('hasLocation').as('loc'),
        __.as('meter2').out('isPartOf').as('meter1'),
        __.as('meter2').out('hasTimeSeries').as('class')
    )

с ужасом:

Exception in thread "main" java.lang.IllegalStateException: The provided match pattern is unsolvable: [[MatchStartStep(_m), VertexStep(OUT,[is],vertex), HasStep([~label.eq(A)]), MatchEndStep], [MatchStartStep(_m2), VertexStep(OUT,[bar],edge), StoreStep(edges), EdgeVertexStep(IN), MatchEndStep(_m1)], [MatchStartStep(_m1), VertexStep(OUT,[foo],edge), StoreStep(edges), EdgeVertexStep(IN), MatchEndStep(_l)], [MatchStartStep(c), VertexStep(OUT,[is],vertex), HasStep([~label.eq(D)]), MatchEndStep], [MatchStartStep(_m1), VertexStep(OUT,[is],vertex), HasStep([~label.eq(B)]), MatchEndStep], [MatchStartStep(_l), VertexStep(OUT,[is],vertex), HasStep([~label.eq(A)]), MatchEndStep], [MatchStartStep(_m1), VertexStep(OUT,[beer],edge), StoreStep(edges), EdgeVertexStep(IN), MatchEndStep(c)]]

Теперь вот похожий, который работает вместо:

g.V().match(
        __.as('loc').has('guid','EGLD').out('instanceOfSupClass').hasLabel('Main_Location'),
        __.as('meter1').out('instanceOfSupClass').hasLabel('Electricity_Meter'),
        __.as('meter2').out('instanceOfSupClass').hasLabel('Electricity_Meter'),
        __.as('class').out('instanceOfSupClass').hasLabel('Cleaned_Electricty_Meter'),
        __.as('meter1').out('hasLocation').as('loc'),
        __.as('meter2').out('isPartOf').as('meter1'),
        __.as('meter1').out('hasTimeSeries').as('class')
    )

Я бы ожидал, что они оба дадут один результат (хотя и разные, так как они разные).

Я бы хотел понять, почему это происходит с ошибкой и, в конце концов, если это ошибка или я что-то упустил.

EDIT: добавить примеры и параллелизмы между игрушечным графом (который не выдает ошибку) и моими реальными запросами (я не могу загрузить пример моего графика)

beer_graph=TinkerGraph.open()
g = beer_graph.traversal()

A = g.addV('A').next()
B = g.addV('B').next()
C = g.addV('C').next()

LOK = g.addV().next()
MOK1 = g.addV().next()
MOK2 = g.addV().next()
COK = g.addV().next()

g.V(LOK).addE('is').to(A)
g.V(MOK1).addE('is').to(B)
g.V(MOK2).addE('is').to(B)
g.V(COK).addE('is').to(C)

g.V(MOK1).addE('foo').to(LOK)
g.V(MOK2).addE('bar').to(MOK1)
g.V(MOK2).addE('beer').to(COK)

LKO = g.addV().property('guid', 'LKO').next()
MKO1 = g.addV().next()
MKO2 = g.addV().next()
CKO = g.addV().next()

g.V(LKO).addE('is').to(A)
g.V(MKO1).addE('is').to(B)
g.V(MKO2).addE('is').to(B)
g.V(CKO).addE('is').to(C)

g.V(MKO1).addE('foo').to(LKO)
g.V(MKO2).addE('bar').to(MKO1)
g.V(MKO1).addE('beer').to(CKO)


g.V().match(
        __.as('_l').has('guid', 'LKO').outE('is').inV().hasLabel('A'),
        __.as('_m1').outE('is').inV().hasLabel('B'),
        __.as('_m2').outE('is').inV().hasLabel('B'),
        __.as('_c').outE('is').inV().hasLabel('C'),
        __.as('_m1').outE('foo').inV().as('_l'),
        __.as('_m2').outE('bar').inV().as('_m1'),
        __.as('_m1').outE('beer').inV().as('_c')
    )

g.V().match(
        __.as('_l').outE('is').inV().hasLabel('A'),
        __.as('_m1').outE('is').inV().hasLabel('B'),
        __.as('_m2').outE('is').inV().hasLabel('B'),
        __.as('_c').outE('is').inV().hasLabel('C'),
        __.as('_m1').outE('foo').inV().as('_l'),
        __.as('_m2').outE('bar').inV().as('_m1'),
        __.as('_m2').outE('beer').inV().as('_c')
    )   

Оба работают и возвращают правильно результат. Теперь, отойдя от игрушечного графа, это мой обход во время выполнения моего проекта:

g.V().match(
        __.as('loc').has('guid','EGLD').out('instanceOfSupClass').hasLabel('Main_Location'),
        __.as('meter1').out('instanceOfSupClass').hasLabel('Electricity_Meter'),
        __.as('meter2').out('instanceOfSupClass').hasLabel('Electricity_Meter'),
        __.as('class').out('instanceOfSupClass').hasLabel('Cleaned_Electricty_Meter'),
        __.as('meter1').out('hasLocation').as('loc'),
        __.as('meter2').out('isPartOf').as('meter1'),
        __.as('meter2').out('hasTimeSeries').as('class')
    )


[
[MatchStartStep(loc), HasStep([guid.eq(EGLD)]), VertexStep(OUT,[instanceOfSupClass],vertex), HasStep([~label.eq(Main_Location)]), MatchEndStep], 
[MatchStartStep(meter1), VertexStep(OUT,[instanceOfSupClass],vertex), HasStep([~label.eq(Electricity_Meter)]), MatchEndStep], 
[MatchStartStep(meter2), VertexStep(OUT,[instanceOfSupClass],vertex), HasStep([~label.eq(Electricity_Meter)]), MatchEndStep], 
[MatchStartStep(class), VertexStep(OUT,[instanceOfSupClass],vertex), HasStep([~label.eq(Cleaned_Electricty_Meter)]), MatchEndStep], 
[MatchStartStep(meter1), VertexStep(OUT,[hasLocation],vertex), MatchEndStep(loc)], 
[MatchStartStep(meter2), VertexStep(OUT,[isPartOf],vertex), MatchEndStep(meter1)], 
[MatchStartStep(meter2), VertexStep(OUT,[hasTimeSeries],vertex), MatchEndStep(class)]
]

По сравнению с скомпилированным предыдущим

g.V().match(
        __.as('_l').has('guid', 'LKO').outE('is').inV().hasLabel('A'),
        __.as('_m1').outE('is').inV().hasLabel('B'),
        __.as('_m2').outE('is').inV().hasLabel('B'),
        __.as('_c').outE('is').inV().hasLabel('C'),
        __.as('_m1').outE('foo').inV().as('_l'),
        __.as('_m2').outE('bar').inV().as('_m1'),
        __.as('_m1').outE('beer').inV().as('_c')
    )

[
[MatchStartStep(_l), HasStep([guid.eq(LKO)]),    VertexStep(OUT,[is],vertex),                   HasStep([~label.eq(A)]), MatchEndStep],
[MatchStartStep(_m1),                VertexStep(OUT,[is],vertex),                   HasStep([~label.eq(B)]), MatchEndStep], 
[MatchStartStep(_m2),                VertexStep(OUT,[is],vertex),                   HasStep([~label.eq(B)]), MatchEndStep], 
[MatchStartStep(_c),                 VertexStep(OUT,[is],vertex),                   HasStep([~label.eq(C)]), MatchEndStep], 
[MatchStartStep(_m1),                VertexStep(OUT,[foo],vertex), MatchEndStep(_l)], 
[MatchStartStep(_m2),                VertexStep(OUT,[bar],vertex), MatchEndStep(_m1)], 
[MatchStartStep(_m1),                VertexStep(OUT,[beer],vertex), MatchEndStep(_c)]
]

Почему исключение "неразрешимый шаблон" и почему изменение графика имеет значение? Если на текущем графике шаблон «неразрешим», я ожидаю пустой результат, а не исключение ...

РЕДАКТИРОВАТЬ 2: обнаружил разницу, не понимая проблемы

Мне удалось восстановить "инкриминированный" сценарий, этот НЕ РАБОТАЕТ ...

g.V().match(
        __.as("_loc").has("guid","EGLD").out("instanceOfSupClass").hasLabel("Main_Location"),
        __.as("_meter1").out("instanceOfSupClass").hasLabel("Electricity_Meter"),
        __.as("_meter1").outE("hasLocation").store("edges").inV().as("_loc"),
        __.as("_meter1").outE("hasTimeSeries").store("edges").inV().as("class"),
        __.as("_meter2").out("instanceOfSupClass").hasLabel("Electricity_Meter"),
        __.as("_meter2").outE("isPartOf").store("edges").inV().as("_meter1"),
        __.as("class").out("instanceOfSupClass").hasLabel("Virtual_Anomaly_Class_Time_Series")
    )

Этот работает ...

g.V().match(
        __.as("_meter2").out("instanceOfSupClass").hasLabel("Electricity_Meter"),
        __.as("_meter2").outE("isPartOf").store("edges").inV().as("_meter1"),
        __.as("_meter1").outE("hasLocation").store("edges").inV().as("_loc"),
        __.as("_meter1").out("instanceOfSupClass").hasLabel("Electricity_Meter"),
        __.as("class").out("instanceOfSupClass").hasLabel("Virtual_Anomaly_Class_Time_Series"),
        __.as("_loc").has("guid","EGLD").out("instanceOfSupClass").hasLabel("Main_Location"),
        __.as("_meter1").outE("hasTimeSeries").store("edges").inV().as("class")
    )

ТАК ЗАКАЗЫ

1 Ответ

0 голосов
/ 22 мая 2019

Должен признать, что я не до конца понимаю код MatchStep.В нем есть какая-то сортировка, но, очевидно, вы не можете полагаться на эту сортировку, чтобы превратить ваш шаблон в решаемый шаблон.

Когда вы создаете шаблоны, вы должны убедиться, что первая меткасоответствует входящему элементу, и все дальнейшие начальные метки будут доступны после начальной метки и связанных с ней конечных меток.Имеет ли это смысл?В качестве примера на современном графике:

gremlin> g.V().match(
......1>     __.as('a').out('knows').as('b'),
......2>     __.as('b').out('created').as('c'))
==>[a:v[1],b:v[4],c:v[5]]
==>[a:v[1],b:v[4],c:v[3]]
gremlin> g.V().match(
......1>     __.as('b').out('created').as('c'),
......2>     __.as('a').out('knows').as('b'))
The provided match pattern is unsolvable: [[MatchStartStep(a), VertexStep(OUT,[knows],vertex), MatchEndStep(b)], [MatchStartStep(b), VertexStep(OUT,[created],vertex), MatchEndStep(c)]]

Первый шаблон легко решаем.От a вы можете перейти к b, и как только вы узнаете, что такое b, вы можете перейти к c.Второй обход только что поменял шаблоны, но легко понять, почему он неразрешим;вы начинаете с b, оттуда вы можете перейти к c, но тогда неясно, откуда исходит a.Обратите внимание, что a.out.b нельзя просто преобразовать в b.in.a, так как некоторые базы данных графов имеют однонаправленные ребра.Однако, если вы знаете, что ребра могут проходить в обоих направлениях, и вы поворачиваете их вручную, то обход будет работать просто:

gremlin> g.V().match(
......1>     __.as('b').out('created').as('c'),
......2>     __.as('b').in('knows').as('a'))
==>[a:v[1],b:v[4],c:v[5]]
==>[a:v[1],b:v[4],c:v[3]]

В вашем примере кода начальная метка на самом деле должна быть _m2 чтобы все остальные метки были разрешены.Почему это работает, даже если вы не указали его как первый стартовый ярлык?Я не знаю, по какой-то причине, алгоритм внутренней сортировки имеет правильный порядок шаблонов, но, как я уже говорил, этого не следует ожидать.

...