Janusgraph索引

1. 索引类型

Janusgraph支持两种不同类型的索引来加速查询处理:graph indexes(图形索引) 和 vertex-centric indexes(顶点中心索引)。图形索引在通过属性定位出一批实体或者边的过程中有较好的性能,而顶点中心索引能够加速图的遍历速度,尤其是顶点具有很多边的时候。

2. 索引特性

2.1 图形索引(Graph indexes)

图形索引是整个图的全局索引结构,通过对实体或者边的属性进行索引来获得更好的选择性,从而加快图遍历的速度。
比如 以下两个检索操作:

g.V().has('name', 'haizhi')
g.E().has('reason', textContains('loves'))

第一个检索是查询出名称为haizhi的所有顶点,第二个检索操作是检索出边的reason属性中含有loves单词,如果没有对这两个属性没有建立索引,这两个操作都会导致全表扫描,效率非常低效。
图形索引分为两种类型:Composite index (组合索引)和 Mixed index(混合索引)

2.1.1 组合索引(Composite Index)

组合索引通过一个或者一组属性组成的固定的属性组合进行等值检索,这些属性必须是预定义且是固定顺序的。
组合索引支持唯一约束,设置为unique,则该属性组合必须保证唯一性。
排序在内存中,成本高。

2.1.2 混合索引(Mixed Index)

使用混合索引遍历顶点或边的时候,可以使用任何预先添加的属性key的组合。混合索引比组合索引更灵活,支持更多的条件谓词,而组合索引只支持相等判断查询。混合索引比组合索引查询速度要慢。
和组合索引不同,混合索引需要配置索引后端,如elasticsearch, solr, luncen。
混合索引支持全文检索、范围查询、地理位置查询等,并且不支持唯一性检查。
排序效率高。

2.2 顶点中心索引(Vertex-centric indexes)

顶点中心索引是为每个顶点建立的本地索引结构,当在大型的graph中,每个vertex存在数千条或者更多的edge,对这些vertex遍历会存在对这些edge的过滤,遍历效率较低,顶点中心索引能够通过本地索引结构加快索引遍历。该索引只支持最左匹配

3.索引生命周期

3.1 索引状态

我们的目标是从索引开始,通过一系列action,最终使索引进入ENABLED状态。
一个索引只能是处于以下几个状态中的一种

  • INSTALLED The index is installed in the system but not yet registered with all instances in the cluster
  • REGISTERED The index is registered with all instances in the cluster but not (yet) enabled
  • ENABLED The index is enabled and in use
  • DISABLED The index is disabled and no longer in use
3.2 索引操作

可以使用 mgmt.updateIndex()对索引进行以下操作

  • REGISTER_INDEX Registers the index with all instances in the graph cluster. After an index is installed, it - must be registered with all graph instances
  • REINDEX Re-builds the index from the graph
  • ENABLE_INDEX Enables the index so that it can be used by the query processing engine. An index must be registered before it can be enabled.
  • DISABLE_INDEX Disables the index in the graph so that it is no longer used.
  • REMOVE_INDEX Removes the index from the graph (optional operation). Only on composite index.

4. 操作索引

索引创建问题
在创建索引的过程中,按照官方给的示例创建索引,发现一直处于INSTALLED状态,无同转变成ENABLED,导致无法对索引REINDEX操作

mgmt = graph.openManagement()
name = mgmt.getPropertyKey('name')
mgmt.buildIndex('byNameComposite',Vertex.class).addKey(name).buildCompositeIndex()
mgmt.commit()
//等待索引生效  (这里有可能发生超时错误)
mgmt.awaitGraphIndexStatus(graph,'byNameComposite').call()
//此时查看会索引会一直处于INSTALLED状态
mgmt = graph.openManagement()
mgmt.printIndexes();
---------------------------------------------------------------------------------------------------
Vertex Index Name              | Type        | Unique    | Backing        | Key:           Status |
---------------------------------------------------------------------------------------------------
byNameComposite                | Composite   | false     | internalindex  | name:       INSTALLED |
---------------------------------------------------------------------------------------------------
Edge Index (VCI) Name          | Type        | Unique    | Backing        | Key:           Status |
---------------------------------------------------------------------------------------------------
Relation Index                 | Type        | Direction | Sort Key       | Order    |     Status |
---------------------------------------------------------------------------------------------------

解决办法

创建字段和创建索引需要处于同一个事务中。创建的索引状态会变成ENABLED,这会造成一个限制,如果想对已经存在的数据无法建立索引
mgmt = graph.openManagement();
//这里创建属性
name = mgmt.makePropertyKey('name').dataType(String.class).cardinality(org.janusgraph.core.Cardinality.SINGLE).make();
mgmt.buildIndex('byNameComposite',Vertex.class).addKey(name).buildCompositeIndex()
mgmt.commit()
mgmt = graph.openManagement();
mgmt.printIndexes()
---------------------------------------------------------------------------------------------------
Vertex Index Name              | Type        | Unique    | Backing        | Key:           Status |
---------------------------------------------------------------------------------------------------
byNameComposite                | Composite   | false     | internalindex  | name:         ENABLED |
---------------------------------------------------------------------------------------------------
Edge Index (VCI) Name          | Type        | Unique    | Backing        | Key:           Status |
---------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------
Relation Index                 | Type        | Direction | Sort Key       | Order    |     Status |
---------------------------------------------------------------------------------------------------

在混合索引中可以先创建一个ENABLED状态的索引,然后再添加已有的字段来规避这个问题

address = mgmt.makePropertyKey('address').dataType(String.class).cardinality(org.janusgraph.core.Cardinality.SINGLE).make();
mgmt.buildIndex('address_mixed_index',Vertex.class).addKey(address).buildMixedIndex("search")
mgmt.commit()
mgmt = graph.openManagement()
mgmt.printIndexes()
==>------------------------------------------------------------------------------------------------
Vertex Index Name              | Type        | Unique    | Backing        | Key:           Status |
---------------------------------------------------------------------------------------------------
byNameComposite                | Composite   | false     | internalindex  | name:         ENABLED |
address_mixed_index            | Mixed       | false     | search         | address:      ENABLED |
---------------------------------------------------------------------------------------------------
Edge Index (VCI) Name          | Type        | Unique    | Backing        | Key:           Status |
---------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------
Relation Index                 | Type        | Direction | Sort Key       | Order    |     Status |
---------------------------------------------------------------------------------------------------

//获取之前创建的name索引,将该字段加到混合索引中
name = mgmt.getPropertyKey('name');
address_mixed_index = mgmt.getGraphIndex('address_mixed_index');
mgmt.addIndexKey(address_mixed_index, name)
mgmt.commit()
mgmt = graph.openManagement()
//此时查看索引的状态为 REGISTERED
mgmt.printIndexes()
==>------------------------------------------------------------------------------------------------
Vertex Index Name              | Type        | Unique    | Backing        | Key:           Status |
---------------------------------------------------------------------------------------------------
byNameComposite                | Composite   | false     | internalindex  | name:         ENABLED |
address_mixed_index            | Mixed       | false     | search         | name:      REGISTERED |
                               |             |           |                | address:      ENABLED |
---------------------------------------------------------------------------------------------------
Edge Index (VCI) Name          | Type        | Unique    | Backing        | Key:           Status |
---------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------
Relation Index                 | Type        | Direction | Sort Key       | Order    |     Status |
---------------------------------------------------------------------------------------------------

//再对索引进行REINDEX操作
mgmt = graph.openManagement()
mgmt.updateIndex(mgmt.getGraphIndex("address_mixed_index"),SchemaAction.REINDEX).get()
mgmt.commit()
//此时状态都是 ENABLED
mgmt.printIndexes()
==>------------------------------------------------------------------------------------------------
Vertex Index Name              | Type        | Unique    | Backing        | Key:           Status |
---------------------------------------------------------------------------------------------------
byNameComposite                | Composite   | false     | internalindex  | name:         ENABLED |
address_mixed_index            | Mixed       | false     | search         | name:         ENABLED |
                               |             |           |                | address:      ENABLED |
---------------------------------------------------------------------------------------------------
Edge Index (VCI) Name          | Type        | Unique    | Backing        | Key:           Status |
---------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------
Relation Index                 | Type        | Direction | Sort Key       | Order    |     Status |
---------------------------------------------------------------------------------------------------
4.1 Composite index

Comosite index通过一个或多个固定的key组合 来获取Vertex Key或Edge,也即查询条件是在Index中固定的。

4.1.1 创建索引
//开启management并创建字段
mgmt = graph.openManagement()
name = mgmt.makePropertyKey('name').dataType(String.class).cardinality(org.janusgraph.core.Cardinality.SINGLE).make()
age = mgmt.makePropertyKey('age').dataType(Integer.class).cardinality(org.janusgraph.core.Cardinality.SINGLE).make()

// 构建根据name查询vertex的组合索引
mgmt.buildIndex('byNameComposite',Vertex.class).addKey(name).buildCompositeIndex()

// 构建根据name和age查询vertex的组合索引
mgmt.buildIndex('byNameAndAgeComposite',Vertex.class).addKey(name).addKey(age).buildCompositeIndex()

mgmt.commit()

4.1.2 重建索引

mgmt = graph.openManagement()
mgmt.updateIndex(mgmt.getGraphIndex("byNameComposite"),SchemaAction.REINDEX).get()
mgmt.updateIndex(mgmt.getGraphIndex("byNameAndAgeComposite"),SchemaAction.REINDEX).get()
mgmt.commit()

需要注意的是,Composite index需要在查询条件完全匹配(必须该索引中所有字段全部用上才可以触发索引)的情况下才能触发,如上面代码,g.V().has(‘name’, ‘hercules’)和g.V().has(‘age’,30).has(‘name’,‘hercules’)都是可以触发索引的,但g.V().has(‘age’,30)则不行,因并未对age建索引。g.V().has(‘name’,‘hercules’).has(‘age’,inside(20,50))也不可以,因只支持精确匹配,不支持范围查询。

4.1.3 唯一索引使用

Composite Index也可以作为图的属性唯一约束使用,如果composite graph index被设置为unique(),则只能存在最多一个对应的属性组合。

mgmt = graph.openManagement()
name = mgmt.makePropertyKey('name').dataType(String.class).cardinality(org.janusgraph.core.Cardinality.SINGLE).make()
mgmt.buildIndex('byNameUnique',Vertex.class).addKey(name).unique().buildCompositeIndex()
mgmt.commit()
4.2 Mixed index

Mixed Index支持通过其中的 任意key的组合 查询Vertex或者Edge。Mix Index使用上更加灵活,而且支持范围查询等(不仅包含相等);从另外一方面说,Mixed index效率要比Composite Index低。
与Composite key不同,Mixed Index需要配置索引后端,JanusGraph可以在一次安装中支持多个索引后端,而且每个索引后端必须使用JanusGraph中配置唯一标识:称为indexing backend name。

4.2.1 创建索引
mgmt = graph.openManagement()
name = mgmt.makePropertyKey('name').dataType(String.class).cardinality(org.janusgraph.core.Cardinality.SINGLE).make()
age = mgmt.makePropertyKey('age').dataType(String.class).cardinality(org.janusgraph.core.Cardinality.SINGLE).make()
mgmt.buildIndex('nameAndAge',Vertex.class).addKey(name).addKey(age).buildMixedIndex("search")
mgmt.commit()

上面的代码建立了一个名为nameAndAge的索引,该索引使用name和age属性构成,并设定其索引后端为"search",对应到配置文件中为:index.serarch.backend,如果叫solrsearch,则需要增加:index.solrsearch.backend配置。
//这些操作会触发创建的nameAndAge索引

g.V().has('name', textContains('hercules')).has('age', inside(20,50))
g.V().has('name', textContains('hercules'))
g.V().has('age', lt(50))
4.2.2 添加属性

对已经存在的索引新增属性

mgmt = graph.openManagement()
//创建一个新的属性
location = mgmt.makePropertyKey('location').dataType(Geoshape.class).make()
nameAndAge = mgmt.getGraphIndex('nameAndAge')

//修改索引
mgmt.addIndexKey(nameAndAge, location)
mgmt.commit()

//对已经存在的数据重建索引
mgmt = graph.openManagement()
mgmt.updateIndex(mgmt.getGraphIndex("nameAndAge"),SchemaAction.REINDEX).get()
mgmt.commit()
4.2.3 对指定的lable数据建立索引

有些情况下,我们不想对图中具有某一label的所有Vertex或Edge进行索引,例如,我们只想对有GOD标签的节点进行索引,此时我们可以使用indexOnly方法表示只索引具有某一Label的Vertex和Edge。如下:

//Never create new indexes while a transaction is activegraph.tx().rollback()
mgmt = graph.openManagement()
name = mgmt.makePropertyKey('name').dataType(String.class).cardinality(org.janusgraph.core.Cardinality.SINGLE).make()
god = mgmt.makeVertexLabel('god').dataType(String.class).cardinality(org.janusgraph.core.Cardinality.SINGLE).make()

//只索引有god这一label的顶点
mgmt.buildIndex('byNameAndLabel',Vertex.class).addKey(name).indexOnly(god).buildCompositeIndex()
mgmt.commit()
4.3 Vertex-centric indexes

Vertex-centric index(顶点中心索引)是为每个vertex建立的本地索引结构,在大型graph中,每个vertex有数千条Edge,在这些vertex中遍历效率将会非常低(需要在内存中过滤符合要求的Edge)。Vertex-centric index可以通过使用本地索引结构加速遍历效率,组合索引只支持最左匹配原则
如:

h = g.V().has('name','hercules').next()
g.V(h).outE('battled').has('time', inside(10,20)).inV()

如果没有vertex-centric index,则需要便利所有的batteled边并找出记录,在边的数量庞大时效率非常低。
建立一个vertex-centric index可以加速查询:

//Never create new indexes while a transaction is activegraph.tx().rollback()
mgmt = graph.openManagement()

//找到一个property key
time = mgmt.makePropertyKey('time').dataType(String.class).cardinality(org.janusgraph.core.Cardinality.SINGLE).make()
// 找到一个label
battled = mgmt.getEdgeLabel('battled')

// 创建vertex-centric index
mgmt.buildEdgeIndex(battled,'battlesByTime',Direction.BOTH,Order.decr, time)
mgmt.commit()

//Wait for the index to become available
mgmt.awaitGraphIndexStatus(graph,'battlesByTime').call()

//Reindex the existing data
mgmt = graph.openManagement()
mgmt.updateIndex(mgmt.getGraphIndex("battlesByTime"),SchemaAction.REINDEX).get()
mgmt.commit()

上面的代码对battled边根据time以降序建立了双向索引。buildEdgeIndex()方法中的第一个参数是要索引的Edge的Label,第二个参数是index的名称,第三个参数是边的方向,BOTH意味着可以使用IN/OUT,如果只设置为某一方向,可以减少一半的存储和维护成本。最后两个参数是index的排序方向,以及要索引的property key,property key可以是多个,order默认为升序(Order.ASC)。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值