计算neo4j图数据库以获得组合结果

时间:2015-12-07 11:05:20

标签: neo4j graph-databases

是否可以创建图形数据库来模拟产品功能(手机),并从该模型生成所有有效的手机组合?。

我已经创建了这样的数据库。

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)

我希望能够获得给定模型的手机的所有有效组合。

结果应为:

产品1:

mobilephone,screen

产品2:

mobilephone,screen,camera,lowrescam,flash

产品3:

mobilephone,screen,camera,hirescam,flash

无效产品是:

mobilephone,screen,camera,lowrescam,hirescam,flash

这是因为该模型不允许两种类型的摄像机都使用CHOOSE1

最终目的是检查是否可以在图形DB中存储/计算特征模型。

我是Neo4j的新手,正在研究模拟行为的可能方法,否则使用标记过渡系统建模。

2 个答案:

答案 0 :(得分:2)

我意识到您询问了Neo4j解决方案,但我想为您提供另一种型号。正如你所说的那样,这听起来像是你处于分析阶段。因此,您可能不需要数据库。

此域的模型的一种方法是作为"特征流"顶点代表"产品问题"并且有向边代表X" has-feature"收率

从源节点和汇聚节点phoneproduct开始。

如果关注点X需要另一个关注点Y,则从X到Y将存在单个边缘。这实际上使得关注Y"强制性"。如果有一个选项,则从X到Y和Z将有多个传出边。网络流中的最终关注点链接到product汇聚节点。所有产品功能的组合成为从源到接收器的所有路径的集合。

以下是Clojure中的示例实现。

有向无环图是一个散列图,顶点为键,顶点向量为值:

(def g
  {:phone [:mobilephone]
   :mobilephone [:screen]
   :screen [:camera :product]
   :camera [:highrescam :lowrescam]
   :highrescam [:flash]
   :lowrescam [:flash]
   :flash [:product]})

在yEd中可视化,我们得到: enter image description here

当您在此网络中从左向右移动时,您将按功能构建产品功能。

我们可以使用从源到接收器的深度优先搜索找到所有路径:

(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])

为手机输入引入触摸屏和键盘选项非常简单:

(def g
  {:phone [:mobilephone]
   :mobilephone [:touchscreen :keyboard]
   :touchscreen [:camera :product]
   :keyboard [:camera :product]
   :camera [:highrescam :lowrescam]
   :highrescam [:flash]
   :lowrescam [:flash]
   :flash [:product]})

再次,yEd中的模型: enter image description here

正如预期的那样,引入新的二进制选项会使路径数增加一倍:

(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会提供allPaths algorithm

答案 1 :(得分:1)

TL; DR

你想要做的是一个坏主意,因为你不能对Neo4j"嘿,我希望每个Phone节点只与Camera节点有一个关系,并且总是有一个Screen,和...." Neo4j中存在约束,但你不能限制这样的事情。

Neo4j是一个数据库,正如每个数据库应该做的那样,它用于存储和使用数据,而不是像你想要的那样创建数据(使用约束创建电话和组件的每个组合)。

这种逻辑应该在你的应用程序中实现,然后使用一个好的数据模型存储在数据库中(我提供的那个似乎 - 不是最好的但是很好)

始终使用标签

像你一样创建节点是没用的,因为你只是创建没有标签,没有属性的空节点。此外,标签可以帮助您确保良好的性能。

实施例

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)

修改

要匹配您的有效手机,您可以这样做:

产品1(只有一个强制项目的手机):

Match (phone:Phone)-[:MANDATORY]->(sc:Component)
WHERE count(sc) = 1
return phone

产品2(电话)

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: "Stackoverflow"})
(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)

查询

然后,您可以使用新的手机节点创建有效组合:

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.

但正如你所看到的,你必须用你的手和一堆请求来创造每一个组合,有点痛苦。