索引

Ultipa 的索引机制将会大大加速针对元数据(点,边)的检索速度,这与传统数据库的索引有相似之处。除此之外,Ultipa 图索引还会为路径检索,K 邻检索等图上检索提速。

Ultipa 具备完全原生开发的 fulltext 全文搜索引擎。 可以针对数据中的长文本进行高效快速的搜索,不仅方便了对元数据的检索,还适用于其他各类图搜索,如 AB, Khop 或者模板等,这是前所未有的。

本章将会介绍:

  • LTE 与索引的区别
  • 创建索引
  • 删除索引
  • 查看索引
  • 全文索引搜索
  • 前缀搜索
  • 模板全文搜索

LTE 与索引

在《实例,图集与属性》章节中我们了解到一种路径检索的加速机制:LTE(Load To Engine), 它们都可以帮助提升检索的速度,但是他们的也存在一些区别:

区别 1:加速对象

LTE 主要加速对象是图上路径搜索,如 AB 路径搜索,K 邻搜索,凡是涉及到图(深度>=1)的搜索,都适合使用 LTE 加速。

索引主要加速对象是元数据搜索,无论是单独的点边搜索,还是路径中的点边过滤,都适用于索引机制。

如果路径搜索中的属性同时 LTE 了并创建了索引, 那么会优先使用 LTE。
如果元数据搜索中的属性同时 LTE 了并创建了索引,那么会优先使用 索引。

区别 2:实现原理

LTE 主要是将所需属性加载到 Ultipa 图计算引擎,引擎可以直接使用,配合算法执行,因此可以降低对磁盘 I/O 的依赖。

索引主要是创建各类索引树,不会加载到内存引擎,直接使用持久化存储中的数据结构进行检索加速,减少了对内存的消耗。

区别 3:内存与磁盘使用

由于 LTE 会加载到引擎中, 因此会占用一些内存,占用空间取决于属性值的数量。同时,为了方便二次加载,会将 LTE 的数据持久化存于磁盘当中。

索引是基于磁盘数据结构提速的一种方式,因此主要会占用一些磁盘空间。

共同点

  • LTE 和索引都可以提速检索性能。
  • LTE 和索引都会耗费一些磁盘空间,保证创建的内容可以被持久化。

创建索引

用户可以根据需求创建索引:

创建索引的[命令]createIndex()

创建索引的[参数] 为 :

名称 类型 规范 描述
fulltext / / 指定创建全文索引
name string / 全文索引名称,用于搜索条件
node_property property / 索引数据参照的点属性
edge_property property / 索引数据参照的边属性

示例 1:为 node 的属性 name 创建索引

createIndex().node_property("desc");

示例 2:为 edge 的属性 amount 创建索引

createIndex().node_property("desc");

示例 3:为 node 的属性 desc 创建全文索引,并命名为 nodeDesc

createIndex().fulltext().node_property("desc").name("nodeDesc");

注:创建全文索引必须增加 fulltext 关键字,并使用 name 为其命名。

删除索引

当不再使用全文索引,为了节省内存和磁盘,可以将其删除。

删除全文索引的 [命令] 为:dropIndex()

名称 类型 规范 描述
name string / 全文索引名称
fulltext / / 指定删除全文索引
node_property string / 删除点属性索引的名称
edge_property string / 删除边属性索引的名称

示例 1:删除点属性名为 age 的索引

dropIndex().node_property("age");

示例 2:删除边属性名为 rank 的索引

dropIndex().edge_property("rank");

示例 3:删除名称为 nodeDesc 的全文索引

dropIndex().fulltext().name(“nodeDesc”)

索引列表

获取索引列表的 [命令] 为:showIndex()

名称 类型 规范 描述
fulltext / / 是否只列举全文索引

示例 1:列出所有索引

showIndex();

示例 2:列出所有全文索引

showIndex().fulltext();

全文过滤器 – 全文搜索

全文过滤器是为了实现 Ultipa 高速全文搜索,对 Ultipa 过滤器进行的扩展。

全文过滤器,由一组树形文本条件组成,这些文本条件最终将会作为 Ultipa Fulltext

engine 的执行依据。

全文搜索的 标识符: ~

全文搜索支持操作符:$in

示例 1:通过全文索引 nodeDesc 进行全文搜索点,搜索 ULTIPA + GRAPH

find().nodes({~nodeDesc: ["Graph", "Ultipa"]}).limit(10).select(*)

示例 2:通过全文索引 edgeInfo 进行全文搜索边,搜索 ULTIPA 或 GRAPH

find().nodes({~edgeInfo : { $in:["Graph", "Ultipa"] }}). select(*)

示例 3:通过全文索引 nodeDesc 进行全文搜索点, 搜索 ULTIPA + GRAPH,或, ULTIPA + QUERY + LANGUAGE

find().nodes({
  ~nodeDesc: {
    $in:[
     ["ULTIPA", "GRAPTH"],
     ["ULTIPA", "QUERY", "LANGUAGE"]
    ]
  }
}).limit(10).select(*)

全文过滤器 – 前缀搜索

用户可以通过全文索引进行前缀匹配搜索。

示例:通过全文索引 nodeName 搜索以 ”ult” 开头的结果

find().nodes({~nodeName : "ult*"})

示例:通过全文索引 nodeName 搜索以 ”ult” 开头或者以“graph”开头的结果

find().nodes({~nodeName : "ult* graph*"})

示例:通过全文索引 edgeInfo 搜索含有“投资”字样的边

find().edges({~edgeInfo : "投资*"})

全文过滤器 – 基于模板的过滤搜索

用户可以方便的使用模板来完成非常强大基于全文搜索模糊搜索。

示例:从 name 属性中含有 “资本” 字样的顶点出发,找到含有“科技”字样的邻居,并且该邻居的邻居的 name 属性中包含有 ”人工智能” 字样

t().n({~name:"资本*"}).re().n({~name:"科技*"}).e().n({~name:"人工智能*"})
.limit(100).select(*)

示例:同上例,把模板中路径的长度进行调整,资本与投资间相隔 3 步、投资与人工智能间相隔 2 步 ,返回 100 条符合过滤搜索条件的路径

t().n({~intro:"资本*"}).e()[:3].n({~name:"投资*"}).e()[:2].n({~name:"人工智能"})
.limit(100).select(*)

示例:从含有“红杉”字样的顶点出发,搜寻在 5-步以内可以到达的含有“高瓴”字样的顶点,返回 100 条可能的路径

t().n({~name: "红杉*"}).e()[:5].n({~name: "高瓴*"}).limit(100).select(*)

注:在一张 GP/LP 或工商类的知识图谱网络中,上面的查询条件相当于把红杉的公司与高瓴的多家公司做了一个深度的自组网。同样的操作无论是人工还是在三查的系统中都是需要大量手工干预或批处理执行,而无法做到像 Ultipa 一样,通过一个 uQL 语句来简单、实时的实现的。

注:以上的全文本搜索的例子中都使用了模糊匹配符号”“,它的使用是为了最大范围的匹配可能 存在的包含被搜索字符串的实体(点、边的属性)。如果不使用“”,那么可能会出现以下的情况:

  • 因为切词而造成该字符串不存在词库中的精准匹配而无匹配结果;
  • 或,因精准匹配存在而直接返回(返回速度较模糊匹配更高,例如从毫秒级  微妙级)。

我们建议在可能的情况下都使用模糊匹配,除非你的全文本搜索中有很明确的精准搜索的诉求,但是这个时候为什么还需要全文搜索呢?