跳转到主要内容

HugeGraph Plugin 机制及插件扩展流程

插件接入计划用于 1.8.0 的共享基础模块 API 时,请按Java/SPI 迁移指南调整并使用配套 artifacts 重新编译。 下方示例描述 1.7.0 API。

背景

  1. HugeGraph 不仅开源开放,而且要做到简单易用,一般用户无需更改源码也能轻松增加插件扩展功能。
  2. HugeGraph 支持多种内置存储后端,也允许用户无需更改现有源码的情况下扩展自定义后端。
  3. HugeGraph 支持全文检索,全文检索功能涉及到各语言分词,目前已内置 7 种分词器(ansj、hanlp、smartcn、jieba、jcseg、mmseg4j、ikanalyzer),也允许用户无需更改现有源码的情况下扩展自定义分词器。

可扩展维度

目前插件方式提供如下几个维度的扩展项:

  • 后端存储
  • 序列化器
  • 自定义配置项
  • 分词器

插件实现机制

  1. HugeGraph 提供插件接口 HugeGraphPlugin,通过 Java SPI 机制支持插件化
  2. HugeGraph 在 HugeGraphPlugin 接口上以静态方法提供了 4 个扩展项注册函数:registerOptions()、registerBackend()、registerSerializer()、registerAnalyzer()
  3. 插件实现者实现相应的 Options、Backend、Serializer 或 Analyzer 的接口
  4. 插件实现者实现 HugeGraphPlugin 接口的register()方法,在该方法中注册上述第 3 点所列的具体实现类,并打成 jar 包
  5. 插件使用者将 jar 包放在 HugeGraph Server 安装目录的plugins目录下,修改相关配置项为插件自定义值,重启即可生效

插件实现流程实例

1 新建一个 maven 项目

1.1 项目名称取名:hugegraph-plugin-demo
1.2 添加hugegraph-core Jar 包依赖

maven pom.xml 详细内容如下。hugegraph.version 应与要兼容的 Server 版本一致;此处以当前主线版本 1.7.0 为例:

 1<?xml version="1.0" encoding="UTF-8"?>
 2
 3<project xmlns="http://maven.apache.org/POM/4.0.0"
 4         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 5         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 6
 7    <modelVersion>4.0.0</modelVersion>
 8    <groupId>org.apache.hugegraph</groupId>
 9    <artifactId>hugegraph-plugin-demo</artifactId>
10    <version>1.0.0</version>
11    <packaging>jar</packaging>
12
13    <name>hugegraph-plugin-demo</name>
14
15    <properties>
16        <hugegraph.version>1.7.0</hugegraph.version>
17    </properties>
18
19    <dependencies>
20        <dependency>
21            <groupId>org.apache.hugegraph</groupId>
22            <artifactId>hugegraph-core</artifactId>
23            <version>${hugegraph.version}</version>
24        </dependency>
25    </dependencies>
26</project>

2 实现扩展功能

2.1 扩展自定义后端
2.1.1 实现接口 BackendStoreProvider
  • 可实现接口:org.apache.hugegraph.backend.store.BackendStoreProvider
  • 或者继承抽象类:org.apache.hugegraph.backend.store.AbstractBackendStoreProvider

以 RocksDB 后端 RocksDBStoreProvider 为例:

 1public class RocksDBStoreProvider extends AbstractBackendStoreProvider {
 2
 3    protected String database() {
 4        return this.graph().toLowerCase();
 5    }
 6
 7    @Override
 8    protected BackendStore newSchemaStore(HugeConfig config, String store) {
 9        return new RocksDBStore.RocksDBSchemaStore(this, this.database(), store);
10    }
11
12    @Override
13    protected BackendStore newGraphStore(HugeConfig config, String store) {
14        return new RocksDBStore.RocksDBGraphStore(this, this.database(), store);
15    }
16
17    @Override
18    protected BackendStore newSystemStore(HugeConfig config, String store) {
19        return new RocksDBStore.RocksDBSystemStore(this, this.database(), store);
20    }
21
22    @Override
23    public String type() {
24        return "rocksdb";
25    }
26
27    @Override
28    public String driverVersion() {
29        return "1.11";
30    }
31}
2.1.2 实现接口 BackendStore

BackendStore 的核心抽象方法如下(接口默认辅助方法略):

 1public interface BackendStore {
 2    // Store name
 3    String store();
 4
 5    // Stored version
 6    String storedVersion();
 7
 8    // Database name
 9    String database();
10
11    // Get the parent provider
12    BackendStoreProvider provider();
13
14    // Get the system schema store
15    SystemSchemaStore systemSchemaStore();
16
17    // Whether it is the storage of schema
18    boolean isSchemaStore();
19
20    // Open/close database
21    void open(HugeConfig config);
22    void close();
23    boolean opened();
24
25    // Initialize/clear database
26    void init();
27    void clear(boolean clearSpace);
28    boolean initialized();
29
30    // Delete all data of database (keep table structure)
31    void truncate();
32
33    // Add/delete data
34    void mutate(BackendMutation mutation);
35
36    // Query data
37    Iterator<BackendEntry> query(Query query);
38    Iterator<Iterator<BackendEntry>> query(Iterator<Query> queries,
39                                           Function<Query, Query> queryWriter,
40                                           HugeGraph hugeGraph);
41    Number queryNumber(Query query);
42
43    // Transaction
44    void beginTx();
45    void commitTx();
46    void rollbackTx();
47
48    // Get metadata by key
49    <R> R metadata(HugeType type, String meta, Object[] args);
50
51    // Backend features
52    BackendFeatures features();
53
54    // Increase next id for specific type
55    void increaseCounter(HugeType type, long increment);
56
57    // Get current counter for a specific type
58    long getCounter(HugeType type);
59}
2.1.3 扩展自定义序列化器

序列化器必须继承抽象类:org.apache.hugegraph.backend.serializer.AbstractSerializer(implements GraphSerializer, SchemaSerializer) 主要接口的定义如下:

 1public interface GraphSerializer {
 2    BackendEntry writeVertex(HugeVertex vertex);
 3    BackendEntry writeOlapVertex(HugeVertex vertex);
 4    BackendEntry writeVertexProperty(HugeVertexProperty<?> prop);
 5    HugeVertex readVertex(HugeGraph graph, BackendEntry entry);
 6    BackendEntry writeEdge(HugeEdge edge);
 7    BackendEntry writeEdgeProperty(HugeEdgeProperty<?> prop);
 8    HugeEdge readEdge(HugeGraph graph, BackendEntry entry);
 9    CIter<Edge> readEdges(HugeGraph graph, BackendEntry bytesEntry);
10    BackendEntry writeIndex(HugeIndex index);
11    HugeIndex readIndex(HugeGraph graph, ConditionQuery query, BackendEntry entry);
12    BackendEntry writeId(HugeType type, Id id);
13    Query writeQuery(Query query);
14}
15
16public interface SchemaSerializer {
17    BackendEntry writeVertexLabel(VertexLabel vertexLabel);
18    VertexLabel readVertexLabel(HugeGraph graph, BackendEntry entry);
19    BackendEntry writeEdgeLabel(EdgeLabel edgeLabel);
20    EdgeLabel readEdgeLabel(HugeGraph graph, BackendEntry entry);
21    BackendEntry writePropertyKey(PropertyKey propertyKey);
22    PropertyKey readPropertyKey(HugeGraph graph, BackendEntry entry);
23    BackendEntry writeIndexLabel(IndexLabel indexLabel);
24    IndexLabel readIndexLabel(HugeGraph graph, BackendEntry entry);
25}
2.1.4 扩展自定义配置项

增加自定义后端时,可能需要增加新的配置项,实现流程主要包括:

  • 增加配置项容器类,并实现接口org.apache.hugegraph.config.OptionHolder
  • 提供单例方法public static OptionHolder instance(),并在对象初始化时调用方法OptionHolder.registerOptions()
  • 增加配置项声明,单值配置项类型为ConfigOption、多值配置项类型为ConfigListOption

以 RocksDB 配置项定义为例:

 1public class RocksDBOptions extends OptionHolder {
 2
 3    private RocksDBOptions() {
 4        super();
 5    }
 6
 7    private static volatile RocksDBOptions instance;
 8
 9    public static synchronized RocksDBOptions instance() {
10        if (instance == null) {
11            instance = new RocksDBOptions();
12            instance.registerOptions();
13        }
14        return instance;
15    }
16
17    public static final ConfigOption<String> DATA_PATH =
18            new ConfigOption<>(
19                    "rocksdb.data_path",
20                    "The path for storing data of RocksDB.",
21                    disallowEmpty(),
22                    "rocksdb-data/data"
23            );
24
25    public static final ConfigOption<String> WAL_PATH =
26            new ConfigOption<>(
27                    "rocksdb.wal_path",
28                    "The path for storing WAL of RocksDB.",
29                    disallowEmpty(),
30                    "rocksdb-data/wal"
31            );
32
33    public static final ConfigListOption<String> DATA_DISKS =
34            new ConfigListOption<>(
35                    "rocksdb.data_disks",
36                    false,
37                    "The optimized disks for storing data of RocksDB. " +
38                    "The format of each element: `STORE/TABLE: /path/disk`." +
39                    "Allowed keys are [g/vertex, g/edge_out, g/edge_in, " +
40                    "g/vertex_label_index, g/edge_label_index, " +
41                    "g/range_int_index, g/range_float_index, " +
42                    "g/range_long_index, g/range_double_index, " +
43                    "g/secondary_index, g/search_index, g/shard_index, " +
44                    "g/unique_index, g/olap]",
45                    null,
46                    String.class,
47                    ImmutableList.of()
48            );
49}
2.2 扩展自定义分词器

分词器需要实现接口org.apache.hugegraph.analyzer.Analyzer,以实现一个 SpaceAnalyzer 空格分词器为例。

 1package org.apache.hugegraph.plugin;
 2
 3import java.util.Arrays;
 4import java.util.HashSet;
 5import java.util.Set;
 6
 7import org.apache.hugegraph.analyzer.Analyzer;
 8
 9public class SpaceAnalyzer implements Analyzer {
10
11    @Override
12    public Set<String> segment(String text) {
13        return new HashSet<>(Arrays.asList(text.split(" ")));
14    }
15}

3. 实现插件接口,并进行注册

插件注册入口为HugeGraphPlugin.register(),自定义插件必须实现该接口方法,在其内部注册上述定义好的扩展项。接口org.apache.hugegraph.plugin.HugeGraphPlugin定义如下:

 1public interface HugeGraphPlugin {
 2
 3    String name();
 4
 5    void register();
 6
 7    String supportsMinVersion();
 8
 9    String supportsMaxVersion();
10}

并且 HugeGraphPlugin 提供了 4 个静态方法用于注册扩展项:

  • registerOptions(String name, String classPath):注册配置项
  • registerBackend(String name, String classPath):注册后端(BackendStoreProvider)
  • registerSerializer(String name, String classPath):注册序列化器
  • registerAnalyzer(String name, String classPath):注册分词器

下面以注册 SpaceAnalyzer 分词器为例:

 1package org.apache.hugegraph.plugin;
 2
 3public class DemoPlugin implements HugeGraphPlugin {
 4
 5    @Override
 6    public String name() {
 7        return "demo";
 8    }
 9
10    @Override
11    public void register() {
12        HugeGraphPlugin.registerAnalyzer("demo", SpaceAnalyzer.class.getName());
13    }
14
15    @Override
16    public String supportsMinVersion() {
17        return "1.7.0";
18    }
19
20    @Override
21    public String supportsMaxVersion() {
22        return "1.8.0";
23    }
24}

4. 配置 SPI 入口

  1. 确保 services 目录存在:hugegraph-plugin-demo/resources/META-INF/services
  2. 在 services 目录下建立文本文件:org.apache.hugegraph.plugin.HugeGraphPlugin
  3. 文件内容如下:org.apache.hugegraph.plugin.DemoPlugin

5. 打 Jar 包

通过 maven 打包,在项目目录下执行命令mvn package,在 target 目录下会生成 Jar 包文件。使用时将该 Jar 包拷到plugins目录,重启服务即可生效。