Mysql против Cypher против Gremlin по запросу союза

Я работаю над проектом, в котором мне нужно давать рекомендации в реальном времени на основе фильтров. Я решил взглянуть на граф БД и начал играть с neo4j и сравнил его производительность с mysql.

ряды о:

 "broadcast": 159844,
 "format": 5,
 "genre": 10,
 "program": 60495

mysql запрос выглядит так:

select f.id, sum(weight) as total
from
(
    select program.id, 15 as weight
    from broadcast
    inner join program on broadcast.programId = program.id
    where broadcast.startedAt > now() and broadcast.startedAt < date_add(now(), INTERVAL +1 DAY)
    group by program.id
union all
    select program.id, 10 as weight
    from broadcast
    inner join program on broadcast.programId = program.id
    inner join genre ON program.genreId = genre.id
    where genre.id in (13) and broadcast.startedAt > now() and broadcast.startedAt < date_add(now(), INTERVAL +1 DAY)
    group by program.id
union all
    select program.id, 5 as weight
    from broadcast
    inner join program on broadcast.programId = program.id
    inner join genre ON program.genreId = genre.id
    inner join format on genre.formatId = format.id
    where format.id = 6 and broadcast.startedAt > now() and broadcast.startedAt < date_add(now(), INTERVAL +1 DAY)
    group by program.id
) f
group by f.id
order by total desc, id desc
limit 0, 50

На моей локальной машине запрос выполняется примерно за 300 мс. Это может быть приемлемо, но менее 100 мс было бы лучше для обработки в реальном времени.

Я также написал с некоторой помощью запрос thinkerpop3:

g.V().hasLabel('broadcast')
.has('startedAt', inside(new Date().getTime(), new Date().getTime() + (1000 * 60 * 60 * 24)))
.in('programBroadcast')
.dedup()
.union(
   filter{true}
     .as('p', 'w').select('p', 'w').by('id').by(constant(15)),
   filter(out('programGenre').has('id', 4))
     .as('p', 'w').select('p', 'w').by('id').by(constant(10)),
   filter(out('programGenre').out('genreFormat').has('id', 4))
     .as('p', 'w').select('p', 'w').by('id').by(constant(5))
)
.group().by(select("p")).by(select("w").sum())
.order(local).by(valueDecr)
.limit(local, 50)

запрос выполняется около 700 мс !!

===== РЕДАКТИРОВАТЬ =====

так как я хотел отобразить профилирование запроса и получил:

Step                                                               Count  Traversers       Time (ms)    % Dur
=============================================================================================================
Neo4jGraphStep([],vertex)                                         220513      220513       14135.788    68.52
HasStep([~label.eq(broadcast)])                                   159844      159844         391.087     1.90
VertexStep(IN,[programBroadcast],vertex)                          159825      159825         267.202     1.30
DedupGlobalStep                                                    60495       60495          95.848     0.46
UnionStep([[LambdaFilterStep(lambda)@[p, w], Pr...                 63247       63247        2008.553     9.74
  LambdaFilterStep(lambda)@[p, w]                                  60495       60495         194.406
  SelectStep([p, w],[value(id), [ConstantStep(1...                 60495       60495         487.158
    ConstantStep(15)                                               60495       60495          24.214
  EndStep                                                          60495       60495         110.575
  TraversalFilterStep([VertexStep(OUT,[programG...                  2070        2070         410.689
    VertexStep(OUT,[programGenre],vertex)                          22540       22540         191.158
    HasStep([id.eq(6)])                                                0           0         140.934
  SelectStep([p, w],[value(id), [ConstantStep(1...                  2070        2070          52.203
    ConstantStep(10)                                                2070        2070           0.654
  EndStep                                                           2070        2070          43.120
  TraversalFilterStep([VertexStep(OUT,[programG...                   682         682         443.347
    VertexStep(OUT,[programGenre],vertex)                          22540       22540         119.115
    VertexStep(OUT,[genreFormat],vertex)                           27510       27510         117.410
    HasStep([id.eq(1)])                                                0           0         133.517
  SelectStep([p, w],[value(id), [ConstantStep(5...                   682         682          43.247
    ConstantStep(5)                                                  682         682           0.217
  EndStep                                                            682         682          44.427
GroupStep([SelectOneStep(p), ProfileStep],[Sele...                     1           1        3583.249    17.37
  SelectOneStep(p)                                                 63247       63247          26.836
  SelectOneStep(w)                                                 63247       63247          81.623
  SumGlobalStep                                                    60495       60495        3107.593
  SelectOneStep(w)                                                     0           0           0.000
  SumGlobalStep                                                        0           0           0.000
UnfoldStep                                                         60495       60495          17.227     0.08
OrderGlobalStep([valueDecr])                                       60495       60495         114.439     0.55
FoldStep                                                               1           1          16.902     0.08
RangeLocalStep(0,10)                                                   1           1           0.081     0.00
SideEffectCapStep([~metrics])                                          1           1           0.215     0.00
- show quoted text -

это показывает, что в 68% случаев g.V() не имеет индекса!

внезапно я попытался найти способ иметь единую начальную точку, поэтому я сделал:

graph.addVertex(label, 'day', 'id', 1)
graph.cypher("CREATE INDEX ON :day(id)")
g.V().hasLabel('broadcast')
.has('startedAt', inside(new Date().getTime(), new Date().getTime() + (1000 * 60 * 60 * 24)))
.map{it.get().addEdge('broadcastDay', g.V().hasLabel('day').has('id', 1).next())}

и теперь запрос выглядит так:

g.V(14727)
.in('broadcastDay')
.in('programBroadcast')
.union(
    filter{true}
.as('p', 'w').select('p', 'w').by('id').by(constant(15)),
   filter(out('programGenre').has('id', 4))
   .as('p', 'w').select('p', 'w').by('id').by(constant(10)),
   filter(out('programGenre').out('genreFormat').has('id', 4))
   .as('p', 'w').select('p', 'w').by('id').by(constant(5))
)
.group().by(select("p")).by(select("w").sum())
.unfold().order().by(valueDecr).fold()
.limit(local, 50)

и время выполнения теперь составляет 137 мс!

===== КОНЕЦ РЕДАКТИРОВАНИЯ =====

В моем случае Neo4j медленнее, чем mysql...

Поэтому я решил сделать запрос в шифре (спасибо этот пост) с этим наивным подход :

WITH [] AS res

MATCH (b:broadcast)-[:programBroadcast]-(p:program)
WHERE b.startedAt > timestamp() and b.startedAt < (timestamp() + 1000 * 60 * 60 * 24)

OPTIONAL MATCH (p)
WITH res, COLLECT({id: p.id, weight: 15}) AS data
WITH res + data AS res

OPTIONAL MATCH (p)-[:programGenre]-(g:genre{id:4})
WITH res, (CASE WHEN g IS NOT NULL THEN COLLECT({id: p.id, weight: 10}) ELSE [] END) AS data
WITH res + data AS res

OPTIONAL MATCH (p)-[:programGenre]-(g:genre)-[:genreFormat]-(f:format{id:4})
WITH res, (CASE WHEN f IS NOT NULL THEN COLLECT({id: p.id, weight: 5}) ELSE [] END) AS data
WITH res + data AS res

UNWIND res AS result
WITH result, result.id as id, SUM(result.weight) as weight
ORDER BY weight DESC
LIMIT 10
RETURN id, weight     

Я около 68614ms !!

Я очень разочарован графической базой данных, но я не понимаю, почему я использовал индексы для всех свойств и установил память Java около 4 г, и она застряла по сравнению с mysql, почему? graph db только для больших данных, где mysql не может выполнить соединение?


person jrweb247    schedule 22.04.2016    source источник
comment
Можете ли вы поделиться моделью данных и тем, как были определены индексы? Также вы пробовали это с другим бэкэндом? Также из любопытства, делаете ли вы правильный прогрев перед измерением времени запроса? (т.е. запустите запрос один раз перед измерением времени)   -  person Pomme.Verte    schedule 22.04.2016
comment
Я очень разочарован графовой базой данных - вы создали шифрованный запрос значительной сложности, возможно, не оптимизированный, возможно, с моделью данных, не оптимизированной для графа, и вы разочаровались... Я думаю, что есть над чем поработать здесь, прежде чем сделать такой вывод.   -  person David Makogon    schedule 23.04.2016
comment
Я прихожу сюда в основном за советом и двигаться вперед, если у вас есть пожалуйста   -  person jrweb247    schedule 23.04.2016
comment
@ D.Mill Я пробовал с титаном 1.0 + кассандрой, результаты были хуже. Кто-то из группы google посоветовал мне посмотреть графики OLAP, оптимизированные для этого типа запроса из-за g.V() (см. редактирование)   -  person jrweb247    schedule 23.04.2016