计算 neo4j 图形数据库以获得组合结果
Computing a neo4j graph database to get combinatory results
是否可以创建一个图形数据库来模拟产品特性 (Phone) 并从该模型生成所有有效的 phone 组合?
我创建了一个这样的数据库。
CREATE
(mobilephone:Phone),
(screen:Component),
(camera:Component),
(lowrescam:Component),
(hirescam:Component),
(flash:Component),
(mobilephone)-[:MANDATORY]->(screen),
(mobilephone)-[:OPTIONAL]->(camera),
(camera)-[:CHOOSE1]->(lowrescam),
(camera)-[:CHOOSE1]->(hirescam),
(camera)-[:REQUIRES]->(flash)
(mobilephone)-[:MANDATORY]->(screen),
(mobilephone)-[:OPTIONAL]->(camera),
(camera)-[:CHOOSE1]->(lowrescam),
(camera)-[:CHOOSE1]->(hirescam),
(camera)-[:REQUIRES]->(flash)
我希望能够获得 phone 给定模型的所有有效组合。
结果应该是:
产品 1:
mobilephone,screen
产品 2:
mobilephone,screen,camera,lowrescam,flash
产品 3:
mobilephone,screen,camera,hirescam,flash
无效产品是:
mobilephone,screen,camera,lowrescam,hirescam,flash
这是因为模型不允许CHOOSE1
的两种相机类型。
最终目的是检查特征模型是否可以 stored/computed 在图形数据库中。
我是 Neo4j 的新手,正在研究建模行为的可能方法,否则使用标记的转换系统建模。
TL;DR
你想做的是个坏主意,因为你不能对 Neo4j 说“嘿,我希望每个 Phone 节点与相机节点只有一个关系,并且总是有一个屏幕, 和....”
Neo4j 中存在约束,但你不能约束这种东西。
Neo4j 是一个数据库,正如每个数据库都应该做的那样,它用于存储和使用数据,而不是像您想要的那样创建数据(使用约束创建 phone 和组件的每个组合)。
这种逻辑应该在你的应用程序中实现,然后使用一个好的数据模型存储在数据库中(我提供的那个似乎 - 不是最好的但是 - 很好)
始终使用标签
像您那样创建节点是没有用的,因为您只是在创建没有标签、没有属性的空节点。此外,标签可帮助您确保良好的性能。
例子
CREATE
(mobilephone:Phone),
(screen:Component),
(camera:Component),
(lowrescam:Component),
(hirescam:Component),
(flash:Component),
(mobilephone)-[:MANDATORY]->(screen),
(mobilephone)-[:OPTIONAL]->(camera),
(camera)-[:CHOOSE1]->(lowrescam),
(camera)-[:CHOOSE1]->(hirescam),
(camera)-[:REQUIRES]->(flash)
编辑
要匹配您的有效 phone,您可以这样做:
产品 1(phone 只有一个必填项):
Match (phone:Phone)-[:MANDATORY]->(sc:Component)
WHERE count(sc) = 1
return phone
产品 2(phone)
Match (phone:Phone)-[:MANDATORY]->(sc:Component),
(phone)-[:OPTIONAL]->(ca:Component),
(phone)-[:CHOOSE1]->(cam:Component),
(cam)-[:REQUIRES]->(f:Component)
WHERE count(cam) = 1;
RETURN phone, sc, ca, cam, f
如您所见,每个案例的请求都非常具体。我认为您可能需要重新考虑您的数据模型,因为我认为这个模型不是一个好模型。
让我向您推荐一个更好的数据模型:
创作
(phone: Phone{name: "Whosebug"})
(sc:Screen:Mandatory {name: "LCD blabla HD 1500000p")//The screen is a Screen, and it's a mandatory
(camera:Camera:Unique {name: "Camera"})//The camera must be unique
(flash:Flash{intensity: "1000"})//The flash is just... a flash
(camera)-[Requires]->(flash)
查询
然后,您可以使用新的 phones 个节点创建有效组合:
MATCH (sc:Screen:Mandatory {name: "LCD blabla HD 1500000p")
CREATE (phone:Phone {name: "Example"})-[:USES]->(sc:Screen)
RETURN phone //and here you have your first combination, a phone with just a screen.
但是如您所见,您必须亲手和一堆请求来创建每个组合,这有点痛苦。
我知道您问的是 Neo4j 解决方案,但我想为您提供另一种模型。正如您所说,这听起来像是您处于分析阶段。因此,您可能不需要数据库。
该领域模型的一种方法是 "feature flow" 网络,其中顶点表示 "product concerns",有向边表示 X "has-feature" Y.
从源节点和汇节点开始 phone
和 product
。
如果关注点 X 需要另一个关注点 Y,则从 X 到 Y 将只有一条边。这实际上使关注点 Y "mandatory"。如果有一个选项,将有多个从 X 到 Y 和 Z 的出边。网络中的最终关注点 link 到 product
汇节点。所有产品特征的组合成为从源到汇的所有路径的集合。
这是 Clojure 中的示例实现。
有向无环图是一个以顶点为键、以顶点向量为值的哈希图:
(def g
{:phone [:mobilephone]
:mobilephone [:screen]
:screen [:camera :product]
:camera [:highrescam :lowrescam]
:highrescam [:flash]
:lowrescam [:flash]
:flash [:product]})
在 yEd 中将其可视化,我们得到:
当您在此网络中从左到右遍历时,您正在逐个功能地构建您的产品。
我们可以使用深度优先搜索从源到汇找到所有路径:
(defn all-paths [graph source sink]
(letfn [(dfs [path visited]
(let [vertex (peek path)]
(if (= sink vertex) [path]
(->> vertex
graph
(remove visited)
(mapcat #(dfs (conj path %) (conj visited %)))))))]
(dfs [source] #{source})))
以 :phone
作为源并以 :product
作为接收器调用,我们得到:
(all-paths g :phone :product)
([:phone :mobilephone :screen :camera :highrescam :flash :product]
[:phone :mobilephone :screen :camera :lowrescam :flash :product]
[:phone :mobilephone :screen :product])
为 phone 输入引入触摸屏和键盘选项很简单:
(def g
{:phone [:mobilephone]
:mobilephone [:touchscreen :keyboard]
:touchscreen [:camera :product]
:keyboard [:camera :product]
:camera [:highrescam :lowrescam]
:highrescam [:flash]
:lowrescam [:flash]
:flash [:product]})
同样,yEd 中的模型:
不出所料,引入新的二元期权使路径数量翻倍:
(all-paths g :phone :product)
([:phone :mobilephone :touchscreen :camera :highrescam :flash :product]
[:phone :mobilephone :touchscreen :camera :lowrescam :flash :product]
[:phone :mobilephone :touchscreen :product]
[:phone :mobilephone :keyboard :camera :highrescam :flash :product]
[:phone :mobilephone :keyboard :camera :lowrescam :flash :product]
[:phone :mobilephone :keyboard :product])
如果您最终决定需要数据库,Neo4j 会提供
全部恢复。
是否可以创建一个图形数据库来模拟产品特性 (Phone) 并从该模型生成所有有效的 phone 组合?
我创建了一个这样的数据库。
CREATE
(mobilephone:Phone),
(screen:Component),
(camera:Component),
(lowrescam:Component),
(hirescam:Component),
(flash:Component),
(mobilephone)-[:MANDATORY]->(screen),
(mobilephone)-[:OPTIONAL]->(camera),
(camera)-[:CHOOSE1]->(lowrescam),
(camera)-[:CHOOSE1]->(hirescam),
(camera)-[:REQUIRES]->(flash)
(mobilephone)-[:MANDATORY]->(screen),
(mobilephone)-[:OPTIONAL]->(camera),
(camera)-[:CHOOSE1]->(lowrescam),
(camera)-[:CHOOSE1]->(hirescam),
(camera)-[:REQUIRES]->(flash)
我希望能够获得 phone 给定模型的所有有效组合。
结果应该是:
产品 1:
mobilephone,screen
产品 2:
mobilephone,screen,camera,lowrescam,flash
产品 3:
mobilephone,screen,camera,hirescam,flash
无效产品是:
mobilephone,screen,camera,lowrescam,hirescam,flash
这是因为模型不允许CHOOSE1
的两种相机类型。
最终目的是检查特征模型是否可以 stored/computed 在图形数据库中。
我是 Neo4j 的新手,正在研究建模行为的可能方法,否则使用标记的转换系统建模。
TL;DR
你想做的是个坏主意,因为你不能对 Neo4j 说“嘿,我希望每个 Phone 节点与相机节点只有一个关系,并且总是有一个屏幕, 和....” Neo4j 中存在约束,但你不能约束这种东西。
Neo4j 是一个数据库,正如每个数据库都应该做的那样,它用于存储和使用数据,而不是像您想要的那样创建数据(使用约束创建 phone 和组件的每个组合)。
这种逻辑应该在你的应用程序中实现,然后使用一个好的数据模型存储在数据库中(我提供的那个似乎 - 不是最好的但是 - 很好)
始终使用标签
像您那样创建节点是没有用的,因为您只是在创建没有标签、没有属性的空节点。此外,标签可帮助您确保良好的性能。
例子
CREATE
(mobilephone:Phone),
(screen:Component),
(camera:Component),
(lowrescam:Component),
(hirescam:Component),
(flash:Component),
(mobilephone)-[:MANDATORY]->(screen),
(mobilephone)-[:OPTIONAL]->(camera),
(camera)-[:CHOOSE1]->(lowrescam),
(camera)-[:CHOOSE1]->(hirescam),
(camera)-[:REQUIRES]->(flash)
编辑
要匹配您的有效 phone,您可以这样做:
产品 1(phone 只有一个必填项):
Match (phone:Phone)-[:MANDATORY]->(sc:Component)
WHERE count(sc) = 1
return phone
产品 2(phone)
Match (phone:Phone)-[:MANDATORY]->(sc:Component),
(phone)-[:OPTIONAL]->(ca:Component),
(phone)-[:CHOOSE1]->(cam:Component),
(cam)-[:REQUIRES]->(f:Component)
WHERE count(cam) = 1;
RETURN phone, sc, ca, cam, f
如您所见,每个案例的请求都非常具体。我认为您可能需要重新考虑您的数据模型,因为我认为这个模型不是一个好模型。
让我向您推荐一个更好的数据模型:
创作
(phone: Phone{name: "Whosebug"})
(sc:Screen:Mandatory {name: "LCD blabla HD 1500000p")//The screen is a Screen, and it's a mandatory
(camera:Camera:Unique {name: "Camera"})//The camera must be unique
(flash:Flash{intensity: "1000"})//The flash is just... a flash
(camera)-[Requires]->(flash)
查询
然后,您可以使用新的 phones 个节点创建有效组合:
MATCH (sc:Screen:Mandatory {name: "LCD blabla HD 1500000p")
CREATE (phone:Phone {name: "Example"})-[:USES]->(sc:Screen)
RETURN phone //and here you have your first combination, a phone with just a screen.
但是如您所见,您必须亲手和一堆请求来创建每个组合,这有点痛苦。
我知道您问的是 Neo4j 解决方案,但我想为您提供另一种模型。正如您所说,这听起来像是您处于分析阶段。因此,您可能不需要数据库。
该领域模型的一种方法是 "feature flow" 网络,其中顶点表示 "product concerns",有向边表示 X "has-feature" Y.
从源节点和汇节点开始 phone
和 product
。
如果关注点 X 需要另一个关注点 Y,则从 X 到 Y 将只有一条边。这实际上使关注点 Y "mandatory"。如果有一个选项,将有多个从 X 到 Y 和 Z 的出边。网络中的最终关注点 link 到 product
汇节点。所有产品特征的组合成为从源到汇的所有路径的集合。
这是 Clojure 中的示例实现。
有向无环图是一个以顶点为键、以顶点向量为值的哈希图:
(def g
{:phone [:mobilephone]
:mobilephone [:screen]
:screen [:camera :product]
:camera [:highrescam :lowrescam]
:highrescam [:flash]
:lowrescam [:flash]
:flash [:product]})
在 yEd 中将其可视化,我们得到:
当您在此网络中从左到右遍历时,您正在逐个功能地构建您的产品。
我们可以使用深度优先搜索从源到汇找到所有路径:
(defn all-paths [graph source sink]
(letfn [(dfs [path visited]
(let [vertex (peek path)]
(if (= sink vertex) [path]
(->> vertex
graph
(remove visited)
(mapcat #(dfs (conj path %) (conj visited %)))))))]
(dfs [source] #{source})))
以 :phone
作为源并以 :product
作为接收器调用,我们得到:
(all-paths g :phone :product)
([:phone :mobilephone :screen :camera :highrescam :flash :product]
[:phone :mobilephone :screen :camera :lowrescam :flash :product]
[:phone :mobilephone :screen :product])
为 phone 输入引入触摸屏和键盘选项很简单:
(def g
{:phone [:mobilephone]
:mobilephone [:touchscreen :keyboard]
:touchscreen [:camera :product]
:keyboard [:camera :product]
:camera [:highrescam :lowrescam]
:highrescam [:flash]
:lowrescam [:flash]
:flash [:product]})
同样,yEd 中的模型:
不出所料,引入新的二元期权使路径数量翻倍:
(all-paths g :phone :product)
([:phone :mobilephone :touchscreen :camera :highrescam :flash :product]
[:phone :mobilephone :touchscreen :camera :lowrescam :flash :product]
[:phone :mobilephone :touchscreen :product]
[:phone :mobilephone :keyboard :camera :highrescam :flash :product]
[:phone :mobilephone :keyboard :camera :lowrescam :flash :product]
[:phone :mobilephone :keyboard :product])
如果您最终决定需要数据库,Neo4j 会提供
全部恢复。