前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >视觉搜索和Neo4j的最后一公里

视觉搜索和Neo4j的最后一公里

作者头像
Happiness And Benefit
发布2018-06-05 16:08:44
2.9K0
发布2018-06-05 16:08:44

最后一公里 ”是电信行业使用的一个术语,指系统为实际使用该系统的客户提供链接。就图形数据库而言,它指的是终端用户可以从图中提取有价值的信息和洞察力。我们已经看到了Graph Search这个概念的例子,允许用户用自然语言表达他们的请求。今天我们会看到另一个例子。我们将利用Neo4j 2.0 的特有的优势功能来完成这项工作,因此请务必阅读关于Neo4j的上一篇文章(Neo4j 2.0 is coming)

我们将使用由NewsBlur塞缪尔·克莱编写的VisualSearch.js。VisualSearch.js增强了能够自动完成分面搜索查询的普通搜索框。可选项很容易自定义并且还有注释说明。你可以在下面的图片中看到它的作用,或者点击它来试着让其演示。

图谱搜索演示
图谱搜索演示

我们之前已经制作了一个Neo4j 2.0图表,其中包括了所有与电影相关的演员,导演,制作人,编剧和观众。

Neo4j 2.0图表
Neo4j 2.0图表

我们需要做的第一件事是为visualsearch.j添加Facets。我们不想手动配置,因为这会很麻烦,我们的图表可能会随着时间而改变。因此,我们将使用“list_labels”来代替获取图的分类的方法:

  get  '/facets'  do 
    content_type : json
    cache_control : public ,  : max_age =>  600 
    facets =  [ ] 
    categories = $neo . list_labels    
    categories . each do  | cat |  
      get_properties ( cat ) . each do  | label | 
        facets <<  { : category => cat ,  : label => cat +  "."  + label } 
      end
    end
    facets . to_json
  end

我们可以做的一件好事是将标签的属性组合在一起,我们没有关于每个标签中属性的固定模式,但是我们可以查询图形,获取一个节点并查看它的属性。

     def get_properties ( category ) 
      cypher =  "MATCH n:#{category} RETURN n LIMIT 1" 
      $neo . execute_query ( cypher ) [ "data" ] . first . first [ "data" ] . keys
    end

这将返回一个JSON数组,内容如下:

[ { "category" : "Writer" , "label" : "Writer.born" } , 
{ "category" : "Writer" , "label" : "Writer.name" } , 
{ "category" : "Actor" , "label" : "Actor.born" } , 
{ "category" : "Actor" , "label" : "Actor.name" } 
...

我们会把它传递给visualsearch.js并生成我们的第一个使用这些分组标签属性的下拉菜单。

生成的下拉菜单
生成的下拉菜单

一旦用户点击其中一个内容,我们将填写该属性的一些可用选项的值。我们可以通过匹配具有我们想要的属性的指定标签的节点并对其进行分组来完成处理,以便我们只获得前25个唯一值。

 get  '/values/:facet/'  do 
    content_type : json

    label , key =  get_label_and_key ( params )
    
    cypher = "MATCH node : # { label }  
              WHERE HAS ( node . # { key } ) 
              RETURN node . # { key } AS label ,  COUNT ( * )
              ORDER BY label
              LIMIT 25 "
    
    $neo . execute_query ( cypher ) [ "data" ] . collect { | x | x . first . to_s } . compact . flatten . to_json
  end

现在我们可以在我们的搜索框中看到一些值。在这个例子中,我们在图中抓取了演员的名字。

显示所有的演员名字
显示所有的演员名字

能显示前25个项很好,但如果我们正在寻找一个名字是Z字母开头的演员,比如“ Zach Grenier ”呢?Visualsearch.js让我们可以接着输入值,它会重新匹配我们的选项。

关键字匹配搜索结果
关键字匹配搜索结果

我们将通过添加术语或我们正在查找的术语的一部分的不区分大小写的正则表达式来增强我们以前的查询。

  get  '/values/:facet/:term'  do 
    content_type : json
    
    label , key =  get_label_and_key ( params )
    
    cypher = "MATCH node : # { label }  
              WHERE HAS ( node . # { key } ) AND node . # { key }  = ~  { term } 
              RETURN node . # { key } AS label ,  COUNT ( * )
              ORDER BY label
              LIMIT 25 "
    
    $neo . execute_query ( cypher ,  { : term =>  "(?i).*"  + params [ : term ]  +  ".*" } ) [ "data" ] . collect { | x | x . first . to_s } . compact . flatten . to_json
  end

一旦我们点击Zach Grenier选项,就会出发事件。返回一条消息告诉我们:

You searched for: Actor.name: “Zach Grenier”. (1 node)

搜索栏在后面显示下一组标签用以下一步查询...

点了Zach Grenier选项
点了Zach Grenier选项

通过vivagraph.js填充我们的图(目前仅包含一个节点)。请参阅此前的vivagraph.js文章,以获取有关这伟大图形可视化库如何工作的更多信息。

自动填充选中的演员
自动填充选中的演员

现在我知道你可能会想我们填充了一个Actor节点,现在只有Movie在我们的下拉菜单中可用。那它是怎么生成的呢?这是这个应用程序的独到之处。我们不是随便抓取任何下一个节点,而是从第一个节点的上下文中构建可用连接的路径。如果我们点击“Movie.title”,我们在封面下面调用以下方法来获得我们的可能性:

post '/connected_values/:facet/'  do 
    content_type : json
    related_label , related_key =  get_label_and_key ( params )
    
    match , where , values =  prepare_query ( params ) 
    last_node =  get_last_node_id ( params )
    
    where . pop
    where <<  "HAS(node#{last_node}.#{related_key})"
    
    cypher   =  prepare_cypher ( match , where ) 
    cypher <<  "WITH LAST(EXTRACT(n in NODES(p) : n.#{related_key}?)) AS label, COUNT(*) AS cnt " 
    cypher <<  "RETURN label ORDER BY label LIMIT 25"    
    
    parameters =  prepare_parameters ( values )
        
    $neo . execute_query ( cypher , parameters ) [ "data" ] . flatten . collect { | d | d . to_s } . to_json
  end

它看起来有点复杂,但我们所做的只是动态构建一个密码查询,最终会看起来像这样:

MATCH p = node0 : Actor -- node1 : Movie
WHERE node0 . name ?  =  { value0 } AND HAS ( node1 . title )  
WITH LAST ( EXTRACT ( n in  NODES ( p )  : n . title ? ) ) AS label ,  COUNT ( * ) AS cnt
RETURN label 
ORDER BY label 
LIMIT 25

这个Cypher查询将使用参数{“value0”=>“Zach Grenier”}执行。它会在图中找到Zach Grenier的Actor节点,然后找到标有“Movie”并与Zach Grenier相关的节点,然后从我们路径中的最后一个节点中提取属性“title”成为Zach Grenier的电影的标题)并给我们返回值。

在我们的图中,我们只有两部与Zach Grenier相关,那就是电影“RescueDawn”和“Twister”。继续并单击Twister:

演员所出演的电影Twister选项
演员所出演的电影Twister选项

我们查询了图形中名为“Zach Grenier”的与电影“Twister”有关的的模式Actor。该图找到这个模式,返回这个模式中的节点和关系,Twister被添加到我们的图中,并与Zach Grenier建立连接。

例如,我们可以创建的模式可以超越单跳。出生于1929年的演员,与“忍者刺客”中的Rick Yune以及其他演员一起出演“落在香杉树的雪花”。

MATCH p = node0 : Actor -- node1 : Movie -- node2 : Actor -- node3 : Movie -- node4 : Actor
WHERE node0 . born ?  =  { value0 } AND node1 . title ?  =  { value1 } AND node2 . name ?  =  { value2 } AND node3 . title ?  =  { value3 } AND HAS ( node4 . name )  
WITH LAST ( EXTRACT ( n in  NODES ( p )  : n .name ? ) ) AS label ,  COUNT ( * ) AS cnt
RETURN label 
ORDER BY label 
LIMIT 25 "

这个查询将以参数{“value0”=> 1929,“value1”=>“Snow Falling on Cedars”,“value2”=>“Rick Yune”,“value3”=>“Ninja Assassin”}执行。模式结尾的演员之一是“Naomie Harris”,一旦我们点击她,我们就会得到这张图:

添加的关系图
添加的关系图

不要只是因为这个想法而接受我所说的。试试现场演示,看看源代码,然后尝试将它指向您自己的Neo4j 2.0 Labeled Graph。

缺了什么?

这是一个可让终端用户快速访问图表的动态UI。但是,细心的你可能注意到少了点什么。关系类型。我们创建和匹配图形的模式只关心连接的节点,而不是连接的方式,这可能是我们省略的图形的一个非常重要的特性。唉,这个小小的项目并不是最后一公里,它只是更进一步,最终我们会达到它。

帮助我解决这些问题。

了解图形的强大功能可以提升数据架构师的技能。不要让这篇博文是你最后一次思考图表。了解Calendar中已有诸多活动之一的图表,并随时关注每周的活动。花点时间从您可能错过的活动中观看这些优秀的Neo4j视频。阅读图形数据库书籍,当然,也可以订阅我的博客并在Twitter上关注我

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档