HugeGraph Plugin mechanism and plug-in extension process

Background

  1. HugeGraph is not only open source and open, but also simple and easy to use. General users can easily add plug-in extension functions without changing the source code.
  2. HugeGraph supports a variety of built-in storage backends, and also allows users to extend custom backends without changing the existing source code.
  3. HugeGraph supports full-text search. The full-text search function involves word segmentation in various languages. Currently, there are 8 built-in Chinese word breakers, and it also allows users to expand custom word breakers without changing the existing source code.

Scalable dimension

Currently, the plug-in method provides extensions in the following dimensions:

  • backend storage
  • serializer
  • Custom configuration items
  • tokenizer

Plug-in implementation mechanism

  1. HugeGraph provides a plug-in interface HugeGraphPlugin, which supports plug-in through the Java SPI mechanism
  2. HugeGraph provides four extension registration functions: registerOptions(), registerBackend(), registerSerializer(),registerAnalyzer()
  3. The plug-in implementer implements the corresponding Options, Backend, Serializer or Analyzer interface
  4. The plug-in implementer implements register()the method of the HugeGraphPlugin interface, registers the specific implementation class listed in the above point 3 in this method, and packs it into a jar package
  5. The plug-in user puts the jar package in the HugeGraph Server installation directory plugins, modifies the relevant configuration items to the plug-in custom value, and restarts to take effect

Plug-in implementation process example

1 Create a new maven project

1.1 Name the project name: hugegraph-plugin-demo
1.2 Add hugegraph-core Jar package dependencies

The details of maven pom.xml are as follows:

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

2 Realize extended functions

2.1 Extending a custom backend
2.1.1 Implement the interface BackendStoreProvider
  • Realizable interfaces: org.apache.hugegraph.backend.store.BackendStoreProvider
  • Or inherit an abstract class:org.apache.hugegraph.backend.store.AbstractBackendStoreProvider

Take the RocksDB backend RocksDBStoreProvider as an example:

  1. public class RocksDBStoreProvider extends AbstractBackendStoreProvider {
  2. protected String database() {
  3. return this.graph().toLowerCase();
  4. }
  5. @Override
  6. protected BackendStore newSchemaStore(String store) {
  7. return new RocksDBSchemaStore(this, this.database(), store);
  8. }
  9. @Override
  10. protected BackendStore newGraphStore(String store) {
  11. return new RocksDBGraphStore(this, this.database(), store);
  12. }
  13. @Override
  14. public String type() {
  15. return "rocksdb";
  16. }
  17. @Override
  18. public String version() {
  19. return "1.0";
  20. }
  21. }
2.1.2 Implement interface BackendStore

The BackendStore interface is defined as follows:

  1. public interface BackendStore {
  2. // Store name
  3. public String store();
  4. // Database name
  5. public String database();
  6. // Get the parent provider
  7. public BackendStoreProvider provider();
  8. // Open/close database
  9. public void open(HugeConfig config);
  10. public void close();
  11. // Initialize/clear database
  12. public void init();
  13. public void clear();
  14. // Add/delete data
  15. public void mutate(BackendMutation mutation);
  16. // Query data
  17. public Iterator<BackendEntry> query(Query query);
  18. // Transaction
  19. public void beginTx();
  20. public void commitTx();
  21. public void rollbackTx();
  22. // Get metadata by key
  23. public <R> R metadata(HugeType type, String meta, Object[] args);
  24. // Backend features
  25. public BackendFeatures features();
  26. // Generate an id for a specific type
  27. public Id nextId(HugeType type);
  28. }
2.1.3 Extending custom serializers

The serializer must inherit the abstract class: org.apache.hugegraph.backend.serializer.AbstractSerializer ( implements GraphSerializer, SchemaSerializer) The main interface is defined as follows:

  1. public interface GraphSerializer {
  2. public BackendEntry writeVertex(HugeVertex vertex);
  3. public BackendEntry writeVertexProperty(HugeVertexProperty<?> prop);
  4. public HugeVertex readVertex(HugeGraph graph, BackendEntry entry);
  5. public BackendEntry writeEdge(HugeEdge edge);
  6. public BackendEntry writeEdgeProperty(HugeEdgeProperty<?> prop);
  7. public HugeEdge readEdge(HugeGraph graph, BackendEntry entry);
  8. public BackendEntry writeIndex(HugeIndex index);
  9. public HugeIndex readIndex(HugeGraph graph, ConditionQuery query, BackendEntry entry);
  10. public BackendEntry writeId(HugeType type, Id id);
  11. public Query writeQuery(Query query);
  12. }
  13. public interface SchemaSerializer {
  14. public BackendEntry writeVertexLabel(VertexLabel vertexLabel);
  15. public VertexLabel readVertexLabel(HugeGraph graph, BackendEntry entry);
  16. public BackendEntry writeEdgeLabel(EdgeLabel edgeLabel);
  17. public EdgeLabel readEdgeLabel(HugeGraph graph, BackendEntry entry);
  18. public BackendEntry writePropertyKey(PropertyKey propertyKey);
  19. public PropertyKey readPropertyKey(HugeGraph graph, BackendEntry entry);
  20. public BackendEntry writeIndexLabel(IndexLabel indexLabel);
  21. public IndexLabel readIndexLabel(HugeGraph graph, BackendEntry entry);
  22. }
2.1.4 Extend custom configuration items

When adding a custom backend, it may be necessary to add new configuration items. The implementation process mainly includes:

  • Add a configuration item container class and implement the interface org.apache.hugegraph.config.OptionHolder
  • Provide a singleton method public static OptionHolder instance(), and call the method when the object is initialized OptionHolder.registerOptions()
  • Add configuration item declaration, single-value configuration item type is ConfigOption, multi-value configuration item type is ConfigListOption

Take the RocksDB configuration item definition as an example:

  1. public class RocksDBOptions extends OptionHolder {
  2. private RocksDBOptions() {
  3. super();
  4. }
  5. private static volatile RocksDBOptions instance;
  6. public static synchronized RocksDBOptions instance() {
  7. if (instance == null) {
  8. instance = new RocksDBOptions();
  9. instance.registerOptions();
  10. }
  11. return instance;
  12. }
  13. public static final ConfigOption<String> DATA_PATH =
  14. new ConfigOption<>(
  15. "rocksdb.data_path",
  16. "The path for storing data of RocksDB.",
  17. disallowEmpty(),
  18. "rocksdb-data"
  19. );
  20. public static final ConfigOption<String> WAL_PATH =
  21. new ConfigOption<>(
  22. "rocksdb.wal_path",
  23. "The path for storing WAL of RocksDB.",
  24. disallowEmpty(),
  25. "rocksdb-data"
  26. );
  27. public static final ConfigListOption<String> DATA_DISKS =
  28. new ConfigListOption<>(
  29. "rocksdb.data_disks",
  30. false,
  31. "The optimized disks for storing data of RocksDB. " +
  32. "The format of each element: `STORE/TABLE: /path/to/disk`." +
  33. "Allowed keys are [graph/vertex, graph/edge_out, graph/edge_in, " +
  34. "graph/secondary_index, graph/range_index]",
  35. null,
  36. String.class,
  37. ImmutableList.of()
  38. );
  39. }
2.2 Extend custom tokenizer

The tokenizer needs to implement the interface org.apache.hugegraph.analyzer.Analyzer, take implementing a SpaceAnalyzer space tokenizer as an example.

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

3. Implement the plug-in interface and register it

The plug-in registration entry is HugeGraphPlugin.register(), the custom plug-in must implement this interface method, and register the extension items defined above inside it. The interface org.apache.hugegraph.plugin.HugeGraphPlugin is defined as follows:

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

And HugeGraphPlugin provides 4 static methods for registering extensions:

  • registerOptions(String name, String classPath): register configuration items
  • registerBackend(String name, String classPath): register backend (BackendStoreProvider)
  • registerSerializer(String name, String classPath): register serializer
  • registerAnalyzer(String name, String classPath): register tokenizer

The following is an example of registering the SpaceAnalyzer tokenizer:

  1. package org.apache.hugegraph.plugin;
  2. public class DemoPlugin implements HugeGraphPlugin {
  3. @Override
  4. public String name() {
  5. return "demo";
  6. }
  7. @Override
  8. public void register() {
  9. HugeGraphPlugin.registerAnalyzer("demo", SpaceAnalyzer.class.getName());
  10. }
  11. }

4. Configure SPI entry

  1. Make sure the services directory exists: hugegraph-plugin-demo/resources/META-INF/services
  2. Create a text file in the services directory: org.apache.hugegraph.plugin.HugeGraphPlugin
  3. The content of the file is as follows: org.apache.hugegraph.plugin.DemoPlugin

5. Make Jar package

Through maven packaging, execute the command in the project directory mvn package, and a Jar package file will be generated in the target directory. Copy the Jar package to the plugins directory when using it, and restart the service to take effect.

Last modified September 19, 2023: fix: update all org.apache packages (#287) (656bcbd6)