让我们说我有一个图表,将食物与酸味,甜味,辛辣味,浓郁味等特性联系起来......
如何查询图表,为我提供一组与每种可能的特征组合相匹配的食品。
即。
图形元组如下所示:
F1 > Spicy
F1 > Sweet
F2 > Sour
F2 > Sweet
F3 > Sour
...
查询应该输出与每种可能的特征组合相匹配的食物组。
Spicy => F1, F2, F3, F4, F5
Spicy & Sweet => F1, F3, F5
Spicy & Sweet & Sour => F3
Spicy & Sweet & Sour @ Tangy => F3
Spicy & Sour => ...
Spicy & Sour & Tangy => ...
Spicy & Tangy => ...
答案 0 :(得分:1)
1)假设以下输入:
UNWIND [ {name: 'F1', traits: ['Spicy', 'Sweet' ]},
{name: 'F2', traits: ['Sour' , 'Sweet' ]},
{name: 'F3', traits: ['Tangy', 'Sour', 'Spicy' ]},
{name: 'F4', traits: ['Tangy', 'Sour', 'Spice', 'Tart']} ] AS food
MERGE (F:Food {name: food.name}) WITH F, food
UNWIND food.traits as trait
MERGE (T:Trait {name: trait})
MERGE (F)-[:hasTrait]->(T)
RETURN F, T
2)现在我们需要获得所有特征组合。为此,我们需要apoc library
:
MATCH (T:Trait)
WITH collect(T) as traits
// Here we count the number of combinations of traits as a power of two
WITH traits, toInt(round(exp( log(2) * size(traits) )))-1 as combCount
// Go through all the combinations
UNWIND RANGE(1, combCount) as combIndex
UNWIND RANGE(0, size(traits)-1 ) as p
// Check whether the trait is present in the combination
CALL apoc.bitwise.op( toInt(round( exp(log(2) * p) )),'&',combIndex) YIELD value
WITH combIndex, collect(CASE WHEN value > 0 THEN traits[p] END) as comb
// Return all combinations of traits
RETURN comb ORDER BY size(comb)
3)现在,对于每个组合,我们需要找到食物的交集点:
MATCH (T:Trait)
WITH collect(T) as traits
// Here we count the number of combinations of traits as a power of two
WITH traits, toInt(round(exp( log(2) * size(traits) )))-1 as combCount
// Go through all the combinations
UNWIND RANGE(1, combCount) as combIndex
UNWIND RANGE(0, size(traits)-1 ) as p
// Check whether the trait is present in the combination
CALL apoc.bitwise.op( toInt(round( exp(log(2) * p) )),'&',combIndex) YIELD value
WITH combIndex, collect(CASE WHEN value > 0 THEN traits[p] END) as comb
// Take foods for the first trait:
WITH comb, head(comb) as ft
OPTIONAL MATCH (ft)<-[:hasTrait]-(F:Food)
// We find the intersection of each food with other traits
WITH comb, collect(F) as testFoods
UNWIND testFoods as food
UNWIND comb as trait
OPTIONAL MATCH p = (food)-[:hasTrait]->(trait)
WITH comb, food, trait, size(collect(p)) as pairs
// Check that the number of crossings for food with traits
// for each combination of the same number of traits
WITH comb, food, collect(CASE WHEN pairs > 0 THEN trait END) as pairs
WITH comb, collect(CASE WHEN size(pairs)=size(comb) THEN food END) as pairs
// Return combinations where there is a common food
WITH comb, pairs WHERE size(pairs)>0
RETURN comb, pairs ORDER BY size(comb)
答案 1 :(得分:0)
请记住,neo4j查询输出的格式是为具有列的行设计的,而不是您想要的输出格式,所以这会让事情变得有点棘手。
我强烈建议您在每一行输出食物,使用布尔列作为每个不同简单特征的成员资格,然后在您的应用程序代码中,将食物对象插入每个特征的集合中。然后使用应用程序逻辑,您可以计算所需的所有特征组合,并执行集合交集以生成它们。
这将使neo4j查询变得非常简单:
MATCH (f:Food)
WITH f
RETURN f.name, EXISTS((f)-[:IS]->(:Trait{name:'tangy'})) AS tangy,
EXISTS((f)-[:IS]->(:Trait{name:'sweet'})) AS sweet,
EXISTS((f)-[:IS]->(:Trait{name:'sour'})) AS sour,
EXISTS((f)-[:IS]->(:Trait{name:'spicy'})) AS spicy
也就是说,如果您决定使用neo4j查询完成整个事情,那么它将会变得混乱,因为您需要跟踪并生成您需要的所有组合。对于交叉口操作,您需要安装APOC procedures library。
在我看来,最好的开始是根据每个特征创建一组食物节点。
MATCH (f:Food)-[:IS]->(:Trait{name:'spicy'})
WITH COLLECT(f) AS spicyFood
MATCH (f:Food)-[:IS]->(:Trait{name:'sour'})
WITH COLLECT(f) AS sourFood, spicyFood
MATCH (f:Food)-[:IS]->(:Trait{name:'sweet'})
WITH COLLECT(f) AS sweetFood, sourFood, spicyFood
MATCH (f:Food)-[:IS]->(:Trait{name:'tangy'})
WITH COLLECT(f) AS tangyFood, sweetFood, sourFood, spicyFood
现在您拥有了这些,您可以与您感兴趣的每个组合进行交叉。
CALL apoc.coll.intersection(tangyFood, sweetFood) YIELD value AS tangySweetFood
CALL apoc.coll.intersection(tangyFood, sourFood) YIELD value AS tangySourFood
CALL apoc.coll.intersection(tangyFood, spicyFood) YIELD value AS tangySpicyFood
CALL apoc.coll.intersection(tangySweetFood, sourFood) YIELD value AS tangySweetSourFood
CALL apoc.coll.intersection(tangySweetFood, spicyFood) YIELD value AS tangySweetSpicyFood
CALL apoc.coll.intersection(tangySourFood, spicyFood) YIELD value AS tangySourSpicyFood
CALL apoc.coll.intersection(tangySweetSourFood, spicyFood) YIELD value AS tangySweetSourSpicyFood
CALL apoc.coll.intersection(sweetFood, sourFood) YIELD value AS sweetSourFood
CALL apoc.coll.intersection(sweetFood, spicyFood) YIELD value AS sweetSpicyFood
CALL apoc.coll.intersection(sweetSourFood, spicyFood) YIELD value AS sweetSourSpicyFood
CALL apoc.coll.intersection(sourFood, spicyFood) YIELD value AS sourSpicyFood
RETURN tangyFood, sweetFood, sourFood, spicyFood,
tangySweetFood, tangySourFood, tangySpicyFood,
tangySweetSourFood, tangySweetSpicyFood, tangySourSpicyFood,
tangySweetSourSpicyFood,
sweetSourFood, sweetSpicyFood,
sweetSourSpicyFood,
sourSpicyFood