feat(hugegraph-struct): initialize module with core type interfaces and project configuration

This commit is contained in:
Tsukilc 2025-09-03 15:26:45 +08:00 committed by imbajin
parent 8bdafb5f3a
commit 3f2edb0d9a
92 changed files with 16682 additions and 8 deletions

View File

@ -100,6 +100,8 @@ header: # `header` section is configurations for source codes license header.
- 'hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/tinkerpop/StructureBasicSuite.java'
- 'hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/opencypher/CypherOpProcessor.java'
- 'hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/opencypher/CypherPlugin.java'
- 'hugegraph-struct/src/main/java/org/apache/hugegraph/type/define/Cardinality.java'
- 'hugegraph-struct/src/main/java/org/apache/hugegraph/type/Namifiable.java'
comment: on-failure # on what condition license-eye will comment on the pull request, `on-failure`, `always`, `never`.
# license-location-threshold specifies the index threshold where the license header can be located,

View File

@ -216,3 +216,5 @@ hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/type/define/C
hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/util/StringEncoding.java from https://github.com/JanusGraph/janusgraph
hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/opencypher/CypherOpProcessor.java from https://github.com/opencypher/cypher-for-gremlin
hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/opencypher/CypherPlugin.java from https://github.com/opencypher/cypher-for-gremlin
hugegraph-struct/src/main/java/org/apache/hugegraph/type/define/Cardinality.java from https://github.com/JanusGraph/janusgraph
hugegraph-struct/src/main/java/org/apache/hugegraph/type/Namifiable.java from https://github.com/JanusGraph/janusgraph

197
hugegraph-struct/pom.xml Normal file
View File

@ -0,0 +1,197 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>hugegraph-struct</artifactId>
<parent>
<groupId>org.apache.hugegraph</groupId>
<artifactId>hugegraph</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<guava.version>25.1-jre</guava.version>
<tinkerpop.version>3.5.1</tinkerpop.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.hugegraph</groupId>
<artifactId>hg-pd-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>jakarta.ws.rs</groupId>
<artifactId>jakarta.ws.rs-api</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.tinkerpop</groupId>
<artifactId>gremlin-test</artifactId>
<version>${tinkerpop.version}</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.9</version>
</dependency>
<dependency>
<groupId>org.apache.hugegraph</groupId>
<artifactId>hugegraph-common</artifactId>
<version>${project.version}</version>
<exclusions>
<exclusion>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.apache.hugegraph</groupId>-->
<!-- <artifactId>hg-pd-client</artifactId>-->
<!-- <version>3.7.1-SNAPSHOT</version>-->
<!-- </dependency>-->
<dependency>
<groupId>org.apache.tinkerpop</groupId>
<artifactId>gremlin-shaded</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>org.mindrot</groupId>
<artifactId>jbcrypt</artifactId>
<version>0.4</version>
</dependency>
<dependency>
<groupId>org.eclipse.collections</groupId>
<artifactId>eclipse-collections-api</artifactId>
<version>10.4.0</version>
</dependency>
<dependency>
<groupId>org.eclipse.collections</groupId>
<artifactId>eclipse-collections</artifactId>
<version>10.4.0</version>
</dependency>
<dependency>
<groupId>it.unimi.dsi</groupId>
<artifactId>fastutil</artifactId>
<version>8.1.0</version>
</dependency>
<dependency>
<groupId>org.lz4</groupId>
<artifactId>lz4-java</artifactId>
<version>1.7.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.10.0</version>
</dependency>
<dependency>
<groupId>org.apdplat</groupId>
<artifactId>word</artifactId>
<version>1.3</version>
<exclusions>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.ansj</groupId>
<artifactId>ansj_seg</artifactId>
<version>5.1.6</version>
</dependency>
<dependency>
<groupId>com.hankcs</groupId>
<artifactId>hanlp</artifactId>
<version>portable-1.5.0</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-smartcn</artifactId>
<version>7.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>7.4.0</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.2</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.huaban</groupId>
<artifactId>jieba-analysis</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>jcseg-core</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>com.chenlb.mmseg4j</groupId>
<artifactId>mmseg4j-core</artifactId>
<version>1.10.0</version>
</dependency>
<dependency>
<groupId>com.janeluo</groupId>
<artifactId>ikanalyzer</artifactId>
<version>2012_u6</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,79 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph;
import java.util.Collection;
import java.util.List;
import org.apache.hugegraph.config.HugeConfig;
import org.apache.hugegraph.util.DateUtil;
import org.apache.hugegraph.id.Id;
import org.apache.hugegraph.schema.EdgeLabel;
import org.apache.hugegraph.schema.IndexLabel;
import org.apache.hugegraph.schema.PropertyKey;
import org.apache.hugegraph.schema.VertexLabel;
/**
* Acturally, it would be better if this interface be called
* "HugeGraphSchemaSupplier".
*/
public interface HugeGraphSupplier {
public List<String> mapPkId2Name(Collection<Id> ids);
public List<String> mapIlId2Name(Collection<Id> ids);
public PropertyKey propertyKey(Id key);
public Collection<PropertyKey> propertyKeys();
public VertexLabel vertexLabelOrNone(Id id);
public boolean existsLinkLabel(Id vertexLabel);
public VertexLabel vertexLabel(Id label);
public VertexLabel vertexLabel(String label);
public default EdgeLabel edgeLabelOrNone(Id id) {
EdgeLabel el = this.edgeLabel(id);
if (el == null) {
el = EdgeLabel.undefined(this, id);
}
return el;
}
public EdgeLabel edgeLabel(Id label);
public EdgeLabel edgeLabel(String label);
public IndexLabel indexLabel(Id id);
public Collection<IndexLabel> indexLabels();
public String name();
public HugeConfig configuration();
default long now() {
return DateUtil.now().getTime();
}
}

View File

@ -0,0 +1,860 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.Log;
import org.apache.tinkerpop.shaded.jackson.core.JsonProcessingException;
import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.apache.hugegraph.exception.HugeException;
import org.apache.hugegraph.exception.NotAllowException;
import org.apache.hugegraph.id.Id;
import org.apache.hugegraph.pd.client.KvClient;
import org.apache.hugegraph.pd.client.PDConfig;
import org.apache.hugegraph.pd.common.PDException;
import org.apache.hugegraph.pd.grpc.kv.KResponse;
import org.apache.hugegraph.pd.grpc.kv.ScanPrefixResponse;
import org.apache.hugegraph.pd.grpc.kv.WatchEvent;
import org.apache.hugegraph.pd.grpc.kv.WatchResponse;
import org.apache.hugegraph.pd.grpc.kv.WatchType;
import org.apache.hugegraph.schema.EdgeLabel;
import org.apache.hugegraph.schema.IndexLabel;
import org.apache.hugegraph.schema.PropertyKey;
import org.apache.hugegraph.schema.SchemaElement;
import org.apache.hugegraph.schema.VertexLabel;
import org.apache.hugegraph.type.HugeType;
public class SchemaDriver {
private static Logger log = Log.logger(SchemaDriver.class);
private static final ObjectMapper MAPPER = new ObjectMapper();
public static final String DELIMITER = "-";
public static final String META_PATH_DELIMITER = "/";
public static final String META_PATH_HUGEGRAPH = "HUGEGRAPH";
public static final String META_PATH_GRAPHSPACE = "GRAPHSPACE";
public static final String META_PATH_GRAPH = "GRAPH";
public static final String META_PATH_CLUSTER = "hg";
public static final String META_PATH_SCHEMA = "SCHEMA";
public static final String META_PATH_GRAPH_CONF = "GRAPH_CONF";
public static final String META_PATH_PROPERTY_KEY = "PROPERTY_KEY";
public static final String META_PATH_VERTEX_LABEL = "VERTEX_LABEL";
public static final String META_PATH_EDGE_LABEL = "EDGE_LABEL";
public static final String META_PATH_INDEX_LABEL = "INDEX_LABEL";
public static final String META_PATH_NAME = "NAME";
public static final String META_PATH_ID = "ID";
public static final String META_PATH_EVENT = "EVENT";
public static final String META_PATH_REMOVE = "REMOVE";
public static final String META_PATH_CLEAR = "CLEAR";
private static final AtomicReference<SchemaDriver> INSTANCE =
new AtomicReference<>();
// Client for accessing PD
private final KvClient<WatchResponse> client;
private SchemaCaches caches;
private SchemaDriver(PDConfig pdConfig, int cacheSize,
long expiration) {
this.client = new KvClient<>(pdConfig);
this.caches = new SchemaCaches(cacheSize, expiration);
this.listenMetaChanges();
log.info(String.format(
"The SchemaDriver initialized successfully, cacheSize = %s," +
" expiration = %s s", cacheSize, expiration / 1000));
}
public static void init(PDConfig pdConfig) {
init(pdConfig, 300, 300 * 1000);
}
public static void init(PDConfig pdConfig, int cacheSize, long expiration) {
SchemaDriver instance = INSTANCE.get();
if (instance != null) {
throw new NotAllowException(
"The SchemaDriver [cacheSize=%s, expiration=%s, " +
"client=%s] has already been initialized and is not " +
"allowed to be initialized again", instance.caches.limit(),
instance.caches.expiration(), instance.client);
}
INSTANCE.compareAndSet(null, new SchemaDriver(pdConfig, cacheSize,
expiration));
}
public static void destroy() {
SchemaDriver instance = INSTANCE.get();
if (instance != null) {
instance.caches.cancelScheduleCacheClean();
instance.caches.destroyAll();
INSTANCE.set(null);
}
}
public SchemaCaches schemaCaches() {
return this.caches;
}
public static SchemaDriver getInstance() {
return INSTANCE.get();
}
private void listenMetaChanges() {
this.listen(graphSpaceRemoveKey(), this::graphSpaceRemoveHandler);
this.listen(graphRemoveKey(), this::graphRemoveHandler);
this.listen(graphClearKey(), this::graphClearHandler);
this.listen(schemaCacheClearKey(), this::schemaCacheClearHandler);
}
private <T> void schemaCacheClearHandler(T response) {
List<String> names = this.extractValuesFromResponse(response);
for (String gs : names) {
String[] arr = gs.split(DELIMITER);
assert arr.length == 2;
this.caches.clear(arr[0], arr[1]);
log.info(String.format(
"Graph '%s' schema clear event is received, deleting all " +
"schema caches under '%s'", gs, gs));
}
}
private <T> void graphClearHandler(T response) {
List<String> names = this.extractValuesFromResponse(response);
for (String gs : names) {
String[] arr = gs.split(DELIMITER);
assert arr.length == 2;
this.caches.clear(arr[0], arr[1]);
log.info(String.format(
"Graph '%s' clear event is received, deleting all " +
"schema caches under '%s'", gs, gs));
}
}
private <T> void graphRemoveHandler(T response) {
List<String> names = this.extractValuesFromResponse(response);
for (String gs : names) {
String[] arr = gs.split(DELIMITER);
assert arr.length == 2;
this.caches.destroy(arr[0], arr[1]);
log.info(String.format(
"Graph '%s' delete event is received, deleting all " +
"schema caches under '%s'", gs, gs));
}
}
private <T> void graphSpaceRemoveHandler(T response) {
List<String> names = this.extractValuesFromResponse(response);
for (String gs : names) {
this.caches.destroy(gs);
log.info(String.format(
"graph space '%s' delete event is received, deleting all " +
"schema caches under '%s'", gs, gs));
}
}
public <T> List<String> extractValuesFromResponse(T response) {
List<String> values = new ArrayList<>();
WatchResponse res = (WatchResponse) response;
for (WatchEvent event : res.getEventsList()) {
// Skip if not PUT event
if (!event.getType().equals(WatchType.Put)) {
return null;
}
String value = event.getCurrent().getValue();
values.add(value);
}
return values;
}
public <T> void listen(String key, Consumer<T> consumer) {
try {
this.client.listen(key, (Consumer<WatchResponse>) consumer);
} catch (PDException e) {
throw new HugeException("Failed to listen '%s' to pd", e, key);
}
}
public Map<String, Object> graphConfig(String graphSpace, String graph) {
String content = this.get(graphConfKey(graphSpace, graph));
if (content == null || content.length() == 0) {
return new HashMap<>();
} else {
return fromJson(content, Map.class);
}
}
public PropertyKey propertyKey(String graphSpace, String graph, Id id,
HugeGraphSupplier schemaGraph) {
SchemaElement pk =
this.caches.get(graphSpace, graph, HugeType.PROPERTY_KEY, id);
if (pk == null) {
pk = getPropertyKey(graphSpace, graph, id, schemaGraph);
E.checkArgument(pk != null, "no such propertyKey: id = '%s'", id);
this.caches.set(graphSpace, graph, HugeType.PROPERTY_KEY, pk.id(), pk);
this.caches.set(graphSpace, graph, HugeType.PROPERTY_KEY, pk.name(), pk);
}
return (PropertyKey) pk;
}
public PropertyKey propertyKey(String graphSpace, String graph,
String name, HugeGraphSupplier schemaGraph) {
SchemaElement pk =
this.caches.get(graphSpace, graph, HugeType.PROPERTY_KEY, name);
if (pk == null) {
pk = getPropertyKey(graphSpace, graph, name, schemaGraph);
E.checkArgument(pk != null, "no such propertyKey: name = '%s'",
name);
this.caches.set(graphSpace, graph, HugeType.PROPERTY_KEY, pk.id(), pk);
this.caches.set(graphSpace, graph, HugeType.PROPERTY_KEY, pk.name(), pk);
}
return (PropertyKey) pk;
}
public List<PropertyKey> propertyKeys(String graphSpace, String graph,
HugeGraphSupplier schemaGraph) {
Map<String, String> propertyKeysKvs =
this.scanWithPrefix(propertyKeyPrefix(graphSpace, graph));
List<PropertyKey> propertyKeys =
new ArrayList<>(propertyKeysKvs.size());
for (String value : propertyKeysKvs.values()) {
PropertyKey pk =
PropertyKey.fromMap(fromJson(value, Map.class), schemaGraph);
this.caches.set(graphSpace, graph, HugeType.PROPERTY_KEY, pk.id(), pk);
this.caches.set(graphSpace, graph, HugeType.PROPERTY_KEY, pk.name(), pk);
propertyKeys.add(pk);
}
return propertyKeys;
}
public List<VertexLabel> vertexLabels(String graphSpace, String graph,
HugeGraphSupplier schemaGraph) {
Map<String, String> vertexLabelKvs = this.scanWithPrefix(
vertexLabelPrefix(graphSpace, graph));
List<VertexLabel> vertexLabels =
new ArrayList<>(vertexLabelKvs.size());
for (String value : vertexLabelKvs.values()) {
VertexLabel vl =
VertexLabel.fromMap(fromJson(value, Map.class),
schemaGraph);
this.caches.set(graphSpace, graph, HugeType.VERTEX_LABEL, vl.id(), vl);
this.caches.set(graphSpace, graph, HugeType.VERTEX_LABEL, vl.name(), vl);
vertexLabels.add(vl);
}
return vertexLabels;
}
public List<EdgeLabel> edgeLabels(String graphSpace, String graph,
HugeGraphSupplier schemaGraph) {
Map<String, String> edgeLabelKvs = this.scanWithPrefix(
edgeLabelPrefix(graphSpace, graph));
List<EdgeLabel> edgeLabels =
new ArrayList<>(edgeLabelKvs.size());
for (String value : edgeLabelKvs.values()) {
EdgeLabel el =
EdgeLabel.fromMap(fromJson(value, Map.class), schemaGraph);
this.caches.set(graphSpace, graph, HugeType.EDGE_LABEL, el.id(), el);
this.caches.set(graphSpace, graph, HugeType.EDGE_LABEL, el.name(), el);
edgeLabels.add(el);
}
return edgeLabels;
}
public List<IndexLabel> indexLabels(String graphSpace, String graph,
HugeGraphSupplier schemaGraph) {
Map<String, String> indexLabelKvs = this.scanWithPrefix(
indexLabelPrefix(graphSpace, graph));
List<IndexLabel> indexLabels =
new ArrayList<>(indexLabelKvs.size());
for (String value : indexLabelKvs.values()) {
IndexLabel il =
IndexLabel.fromMap(fromJson(value, Map.class), schemaGraph);
this.caches.set(graphSpace, graph, HugeType.INDEX_LABEL, il.id(), il);
this.caches.set(graphSpace, graph, HugeType.INDEX_LABEL, il.name(), il);
indexLabels.add(il);
}
return indexLabels;
}
private String propertyKeyPrefix(String graphSpace, String graph) {
// HUGEGRAPH/{cluster}/GRAPHSPACE/{graphspace}/GRAPH/{graph
// }/SCHEMA/PROPERTY_KEY/NAME
return stringJoin(META_PATH_DELIMITER,
META_PATH_HUGEGRAPH,
META_PATH_CLUSTER,
META_PATH_GRAPHSPACE,
graphSpace,
graph,
META_PATH_SCHEMA,
META_PATH_PROPERTY_KEY,
META_PATH_NAME);
}
private String vertexLabelPrefix(String graphSpace, String graph) {
// HUGEGRAPH/{cluster}/GRAPHSPACE/{graphspace}/GRAPH/{graph
// }/SCHEMA/VERTEX_LABEL/NAME
return stringJoin(META_PATH_DELIMITER,
META_PATH_HUGEGRAPH,
META_PATH_CLUSTER,
META_PATH_GRAPHSPACE,
graphSpace,
graph,
META_PATH_SCHEMA,
META_PATH_VERTEX_LABEL,
META_PATH_NAME);
}
private String edgeLabelPrefix(String graphSpace, String graph) {
// HUGEGRAPH/{cluster}/GRAPHSPACE/{graphspace}/GRAPH/{graph
// }/SCHEMA/EDGELABEL/NAME
return stringJoin(META_PATH_DELIMITER,
META_PATH_HUGEGRAPH,
META_PATH_CLUSTER,
META_PATH_GRAPHSPACE,
graphSpace,
graph,
META_PATH_SCHEMA,
META_PATH_EDGE_LABEL,
META_PATH_NAME);
}
private String indexLabelPrefix(String graphSpace, String graph) {
// HUGEGRAPH/{cluster}/GRAPHSPACE/{graphspace}/GRAPH/{graph
// }/SCHEMA/INDEX_LABEL/NAME
return stringJoin(META_PATH_DELIMITER,
META_PATH_HUGEGRAPH,
META_PATH_CLUSTER,
META_PATH_GRAPHSPACE,
graphSpace,
graph,
META_PATH_SCHEMA,
META_PATH_INDEX_LABEL,
META_PATH_NAME);
}
public VertexLabel vertexLabel(String graphSpace, String graph, Id id,
HugeGraphSupplier schemaGraph) {
SchemaElement vl =
this.caches.get(graphSpace, graph, HugeType.VERTEX_LABEL, id);
if (vl == null) {
vl = getVertexLabel(graphSpace, graph, id, schemaGraph);
E.checkArgument(vl != null, "no such vertex label: id = '%s'", id);
this.caches.set(graphSpace, graph, HugeType.VERTEX_LABEL, vl.id(), vl);
this.caches.set(graphSpace, graph, HugeType.VERTEX_LABEL, vl.name(), vl);
}
return (VertexLabel) vl;
}
public VertexLabel vertexLabel(String graphSpace, String graph,
String name, HugeGraphSupplier schemaGraph) {
SchemaElement vl =
this.caches.get(graphSpace, graph, HugeType.VERTEX_LABEL, name);
if (vl == null) {
vl = getVertexLabel(graphSpace, graph, name, schemaGraph);
E.checkArgument(vl != null, "no such vertex label: name = '%s'",
name);
this.caches.set(graphSpace, graph, HugeType.VERTEX_LABEL, vl.id(), vl);
this.caches.set(graphSpace, graph, HugeType.VERTEX_LABEL, vl.name(), vl);
}
return (VertexLabel) vl;
}
public EdgeLabel edgeLabel(String graphSpace, String graph, Id id,
HugeGraphSupplier schemaGraph) {
SchemaElement el =
this.caches.get(graphSpace, graph, HugeType.EDGE_LABEL, id);
if (el == null) {
el = getEdgeLabel(graphSpace, graph, id, schemaGraph);
E.checkArgument(el != null, "no such edge label: id = '%s'", id);
this.caches.set(graphSpace, graph, HugeType.EDGE_LABEL, el.id(), el);
this.caches.set(graphSpace, graph, HugeType.EDGE_LABEL, el.name(), el);
}
return (EdgeLabel) el;
}
public EdgeLabel edgeLabel(String graphSpace, String graph, String name,
HugeGraphSupplier schemaGraph) {
SchemaElement el =
this.caches.get(graphSpace, graph, HugeType.EDGE_LABEL, name);
if (el == null) {
el = getEdgeLabel(graphSpace, graph, name, schemaGraph);
E.checkArgument(el != null, "no such edge label: name = '%s'",
name);
this.caches.set(graphSpace, graph, HugeType.EDGE_LABEL, el.id(), el);
this.caches.set(graphSpace, graph, HugeType.EDGE_LABEL, el.name(), el);
}
return (EdgeLabel) el;
}
public IndexLabel indexLabel(String graphSpace, String graph, Id id,
HugeGraphSupplier schemaGraph) {
SchemaElement il =
this.caches.get(graphSpace, graph, HugeType.INDEX_LABEL, id);
if (il == null) {
il = getIndexLabel(graphSpace, graph, id, schemaGraph);
E.checkArgument(il != null, "no such index label: id = '%s'", id);
this.caches.set(graphSpace, graph, HugeType.INDEX_LABEL, il.id(), il);
this.caches.set(graphSpace, graph, HugeType.INDEX_LABEL, il.name(), il);
}
return (IndexLabel) il;
}
public IndexLabel indexLabel(String graphSpace, String graph, String name,
HugeGraphSupplier schemaGraph) {
SchemaElement il =
this.caches.get(graphSpace, graph, HugeType.INDEX_LABEL, name);
if (il == null) {
il = getIndexLabel(graphSpace, graph, name, schemaGraph);
E.checkArgument(il != null, "no such index label: name = '%s'",
name);
this.caches.set(graphSpace, graph, HugeType.INDEX_LABEL, il.id(), il);
this.caches.set(graphSpace, graph, HugeType.INDEX_LABEL, il.name(), il);
}
return (IndexLabel) il;
}
private String get(String key) {
try {
KResponse response = this.client.get(key);
return response.getValue();
} catch (PDException e) {
throw new HugeException("Failed to get '%s' from pd", e, key);
}
}
private Map<String, String> scanWithPrefix(String prefix) {
try {
ScanPrefixResponse response = this.client.scanPrefix(prefix);
return response.getKvsMap();
} catch (PDException e) {
throw new HugeException("Failed to scanWithPrefix '%s' from pd", e, prefix);
}
}
private PropertyKey getPropertyKey(String graphSpace, String graph,
Id propertyKey, HugeGraphSupplier schemaGraph) {
String content =
this.get(propertyKeyIdKey(graphSpace, graph, propertyKey));
if (content == null || content.length() == 0) {
return null;
} else {
return PropertyKey.fromMap(fromJson(content, Map.class), schemaGraph);
}
}
private PropertyKey getPropertyKey(String graphSpace, String graph,
String propertyKey, HugeGraphSupplier schemaGraph) {
String content =
this.get(propertyKeyNameKey(graphSpace, graph, propertyKey));
if (content == null || content.length() == 0) {
return null;
} else {
return PropertyKey.fromMap(fromJson(content, Map.class), schemaGraph);
}
}
private VertexLabel getVertexLabel(String graphSpace, String graph,
Id vertexLabel, HugeGraphSupplier schemaGraph) {
String content =
this.get(vertexLabelIdKey(graphSpace, graph, vertexLabel));
if (content == null || content.length() == 0) {
return null;
} else {
return VertexLabel.fromMap(fromJson(content, Map.class), schemaGraph);
}
}
private VertexLabel getVertexLabel(String graphSpace, String graph,
String vertexLabel, HugeGraphSupplier schemaGraph) {
String content =
this.get(vertexLabelNameKey(graphSpace, graph, vertexLabel));
if (content == null || content.length() == 0) {
return null;
} else {
return VertexLabel.fromMap(fromJson(content, Map.class), schemaGraph);
}
}
private EdgeLabel getEdgeLabel(String graphSpace, String graph,
Id edgeLabel, HugeGraphSupplier schemaGraph) {
String content =
this.get(edgeLabelIdKey(graphSpace, graph, edgeLabel));
if (content == null || content.length() == 0) {
return null;
} else {
return EdgeLabel.fromMap(fromJson(content, Map.class), schemaGraph);
}
}
private EdgeLabel getEdgeLabel(String graphSpace, String graph,
String edgeLabel, HugeGraphSupplier schemaGraph) {
String content =
this.get(edgeLabelNameKey(graphSpace, graph, edgeLabel));
if (content == null || content.length() == 0) {
return null;
} else {
return EdgeLabel.fromMap(fromJson(content, Map.class), schemaGraph);
}
}
private IndexLabel getIndexLabel(String graphSpace, String graph,
Id indexLabel, HugeGraphSupplier schemaGraph) {
String content =
this.get(indexLabelIdKey(graphSpace, graph, indexLabel));
if (content == null || content.length() == 0) {
return null;
} else {
return IndexLabel.fromMap(fromJson(content, Map.class), schemaGraph);
}
}
private IndexLabel getIndexLabel(String graphSpace, String graph,
String indexLabel,
HugeGraphSupplier schemaGraph) {
String content =
this.get(indexLabelNameKey(graphSpace, graph, indexLabel));
if (content == null || content.length() == 0) {
return null;
} else {
return IndexLabel.fromMap(fromJson(content, Map.class),
schemaGraph);
}
}
private <T> T fromJson(String json, Class<T> clazz) {
E.checkState(json != null, "Json value can't be null for '%s'",
clazz.getSimpleName());
try {
return MAPPER.readValue(json, clazz);
} catch (IOException e) {
throw new HugeException("Can't read json: %s", e, e.getMessage());
}
}
private String toJson(Object object) {
try {
return MAPPER.writeValueAsString(object);
} catch (JsonProcessingException e) {
throw new HugeException("Can't write json: %s", e, e.getMessage());
}
}
private String propertyKeyIdKey(String graphSpace, String graph, Id id) {
return idKey(graphSpace, graph, id, HugeType.PROPERTY_KEY);
}
private String propertyKeyNameKey(String graphSpace, String graph,
String name) {
return nameKey(graphSpace, graph, name, HugeType.PROPERTY_KEY);
}
private String vertexLabelIdKey(String graphSpace, String graph, Id id) {
return idKey(graphSpace, graph, id, HugeType.VERTEX_LABEL);
}
private String vertexLabelNameKey(String graphSpace, String graph,
String name) {
return nameKey(graphSpace, graph, name, HugeType.VERTEX_LABEL);
}
private String edgeLabelIdKey(String graphSpace, String graph, Id id) {
return idKey(graphSpace, graph, id, HugeType.EDGE_LABEL);
}
private String edgeLabelNameKey(String graphSpace, String graph,
String name) {
return nameKey(graphSpace, graph, name, HugeType.EDGE_LABEL);
}
private String indexLabelIdKey(String graphSpace, String graph, Id id) {
return idKey(graphSpace, graph, id, HugeType.INDEX_LABEL);
}
private String indexLabelNameKey(String graphSpace, String graph,
String name) {
return nameKey(graphSpace, graph, name, HugeType.INDEX_LABEL);
}
private String graphSpaceRemoveKey() {
// HUGEGRAPH/{cluster}/EVENT/GRAPHSPACE/REMOVE
return stringJoin(META_PATH_DELIMITER,
META_PATH_HUGEGRAPH,
META_PATH_CLUSTER,
META_PATH_EVENT,
META_PATH_GRAPHSPACE,
META_PATH_REMOVE);
}
private String graphConfKey(String graphSpace, String graph) {
// HUGEGRAPH/{cluster}/GRAPHSPACE/{graphspace}/GRAPH_CONF/{graph}
return stringJoin(META_PATH_DELIMITER,
META_PATH_HUGEGRAPH,
META_PATH_CLUSTER,
META_PATH_GRAPHSPACE,
graphSpace,
META_PATH_GRAPH_CONF,
graph);
}
private String nameKey(String graphSpace, String graph,
String name, HugeType type) {
// HUGEGRAPH/hg/GRAPHSPACE/{graphspace}/{graph}/SCHEMA
// /{META_PATH_TYPE}/NAME/{name}
return stringJoin(META_PATH_DELIMITER,
META_PATH_HUGEGRAPH,
META_PATH_CLUSTER,
META_PATH_GRAPHSPACE,
graphSpace,
graph,
META_PATH_SCHEMA,
hugeType2MetaPath(type),
META_PATH_NAME,
name);
}
private String idKey(String graphSpace, String graph,
Id id, HugeType type) {
// HUGEGRAPH/hg/GRAPHSPACE/{graphspace}/{graph}/SCHEMA
// /{META_PATH_TYPE}/ID/{id}
return stringJoin(META_PATH_DELIMITER,
META_PATH_HUGEGRAPH,
META_PATH_CLUSTER,
META_PATH_GRAPHSPACE,
graphSpace,
graph,
META_PATH_SCHEMA,
hugeType2MetaPath(type),
META_PATH_ID,
id.asString());
}
private String schemaCacheClearKey() {
// HUGEGRAPH/{cluster}/EVENT/GRAPH/SCHEMA/CLEAR
return stringJoin(META_PATH_DELIMITER,
META_PATH_HUGEGRAPH,
META_PATH_CLUSTER,
META_PATH_EVENT,
META_PATH_GRAPH,
META_PATH_SCHEMA,
META_PATH_CLEAR);
}
private String graphClearKey() {
// HUGEGRAPH/{cluster}/EVENT/GRAPH/CLEAR
return stringJoin(META_PATH_DELIMITER,
META_PATH_HUGEGRAPH,
META_PATH_CLUSTER,
META_PATH_EVENT,
META_PATH_GRAPH,
META_PATH_CLEAR);
}
private String graphRemoveKey() {
// HUGEGRAPH/{cluster}/EVENT/GRAPH/REMOVE
return stringJoin(META_PATH_DELIMITER,
META_PATH_HUGEGRAPH,
META_PATH_CLUSTER,
META_PATH_EVENT,
META_PATH_GRAPH,
META_PATH_REMOVE);
}
private String hugeType2MetaPath(HugeType type) {
String schemaType = null;
switch (type) {
case PROPERTY_KEY:
schemaType = META_PATH_PROPERTY_KEY;
break;
case VERTEX_LABEL:
schemaType = META_PATH_VERTEX_LABEL;
break;
case EDGE_LABEL:
schemaType = META_PATH_EDGE_LABEL;
break;
case INDEX_LABEL:
schemaType = META_PATH_INDEX_LABEL;
break;
default:
throw new AssertionError(String.format(
"Invalid HugeType : %s", type));
}
return schemaType;
}
private static String stringJoin(String delimiter, String... parts) {
StringBuilder builder = new StringBuilder();
int size = parts.length;
for (int i = 0; i < size; i++) {
builder.append(parts[i]);
if (i < size - 1) {
builder.append(delimiter);
}
}
return builder.toString();
}
private static final class SchemaCaches {
private final int limit;
private final long expiration;
private final Timer timer;
private ConcurrentHashMap<String, ConcurrentHashMap<String,
SchemaElement>> caches;
public SchemaCaches(int limit, long expiration) {
this.expiration = expiration;
this.limit = limit;
this.timer = new Timer();
this.caches = new ConcurrentHashMap<>();
scheduleCacheCleanup();
}
public int limit() {
return this.limit;
}
public long expiration() {
return this.expiration;
}
private void scheduleCacheCleanup() {
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
log.debug("schedule clear schema caches");
clearAll();
}
}, expiration, expiration);
}
public void cancelScheduleCacheClean() {
timer.cancel();
}
public SchemaElement get(String graphSpace, String graph, HugeType type,
Id id) {
return get(graphSpace, graph, type, id.asString());
}
public SchemaElement get(String graphSpace, String graph, HugeType type,
String name) {
String graphName = stringJoin(DELIMITER, graphSpace, graph);
if (this.caches.get(graphName) == null) {
this.caches.put(graphName, new ConcurrentHashMap<>(this.limit));
}
return this.caches.get(graphName)
.get(stringJoin(DELIMITER, type.string(), name));
}
public void set(String graphSpace, String graph, HugeType type, Id id,
SchemaElement value) {
set(graphSpace, graph, type, id.asString(), value);
}
public void set(String graphSpace, String graph, HugeType type,
String name, SchemaElement value) {
String graphName = stringJoin(DELIMITER, graphSpace, graph);
ConcurrentHashMap<String, SchemaElement>
schemaCaches = this.caches.get(graphName);
if (schemaCaches == null) {
schemaCaches = this.caches.put(graphName, new ConcurrentHashMap<>(this.limit));
}
if (schemaCaches.size() >= limit) {
log.info(String.format(
"The current '%s''s schemaCaches size '%s' reached " +
"limit '%s'", graphName, schemaCaches.size(), limit));
return;
}
schemaCaches.put(stringJoin(DELIMITER, type.string(), name),
value);
log.debug(String.format("graph '%s' add schema caches '%s'",
graphName,
stringJoin(DELIMITER, type.string(),
name)));
}
public void remove(String graphSpace, String graph, HugeType type,
Id id) {
remove(graphSpace, graph, type, id.asString());
}
public void remove(String graphSpace, String graph, HugeType type,
String name) {
String graphName = stringJoin(DELIMITER, graphSpace, graph);
ConcurrentHashMap<String, SchemaElement>
schemaCaches = this.caches.get(graphName);
schemaCaches.remove(stringJoin(DELIMITER, type.string(), name));
}
public void clearAll() {
for (String key : this.caches.keySet()) {
log.debug(String.format("graph in '%s' schema caches clear",
key));
this.caches.get(key).clear();
}
}
public void clear(String graphSpace, String graph) {
ConcurrentHashMap<String, SchemaElement>
schemaCaches =
this.caches.get(stringJoin(DELIMITER, graphSpace, graph));
if (schemaCaches != null) {
schemaCaches.clear();
}
}
public void destroyAll() {
this.caches.clear();
}
public void destroy(String graphSpace, String graph) {
this.caches.remove(stringJoin(DELIMITER, graphSpace, graph));
}
public void destroy(String graphSpace) {
for (String key : this.caches.keySet()) {
String gs = key.split(DELIMITER)[0];
if (gs.equals(graphSpace)) {
this.caches.remove(key);
}
}
}
}
}

View File

@ -0,0 +1,182 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph;
import org.apache.hugegraph.HugeGraphSupplier;
import org.apache.hugegraph.SchemaDriver;
import org.apache.hugegraph.id.Id;
import org.apache.hugegraph.pd.client.PDConfig;
import org.apache.hugegraph.schema.*;
import org.apache.commons.configuration2.Configuration;
import org.apache.commons.configuration2.MapConfiguration;
import org.apache.hugegraph.config.HugeConfig;
import org.apache.hugegraph.util.E;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
public class SchemaGraph implements HugeGraphSupplier {
private final String graphSpace;
private final String graph;
private final PDConfig pdConfig;
private HugeConfig config;
private final SchemaDriver schemaDriver;
public SchemaGraph(String graphSpace, String graph, PDConfig pdConfig) {
this.graphSpace = graphSpace;
this.graph = graph;
this.pdConfig = pdConfig;
this.schemaDriver = schemaDriverInit();
this.config = this.loadConfig();
}
private SchemaDriver schemaDriverInit() {
if (SchemaDriver.getInstance() == null) {
synchronized (SchemaDriver.class) {
if (SchemaDriver.getInstance() == null) {
SchemaDriver.init(this.pdConfig);
}
}
}
return SchemaDriver.getInstance();
}
private HugeConfig loadConfig() {
// Load configuration from PD
Map<String, Object> configs =
schemaDriver.graphConfig(this.graphSpace, this.graph);
Configuration propConfig = new MapConfiguration(configs);
return new HugeConfig(propConfig);
}
@Override
public List<String> mapPkId2Name(Collection<Id> ids) {
List<String> names = new ArrayList<>(ids.size());
for (Id id : ids) {
SchemaElement schema = this.propertyKey(id);
names.add(schema.name());
}
return names;
}
@Override
public List<String> mapIlId2Name(Collection<Id> ids) {
List<String> names = new ArrayList<>(ids.size());
for (Id id : ids) {
SchemaElement schema = this.indexLabel(id);
names.add(schema.name());
}
return names;
}
@Override
public HugeConfig configuration(){
return this.config;
}
@Override
public PropertyKey propertyKey(Id id) {
return schemaDriver.propertyKey(this.graphSpace, this.graph, id, this);
}
public PropertyKey propertyKey(String name) {
return schemaDriver.propertyKey(this.graphSpace, this.graph, name, this);
}
@Override
public Collection<PropertyKey> propertyKeys() {
// TODO
return null;
}
@Override
public VertexLabel vertexLabelOrNone(Id id) {
VertexLabel vl = vertexLabel(id);
if (vl == null) {
vl = VertexLabel.undefined(null, id);
}
return vl;
}
@Override
public boolean existsLinkLabel(Id vertexLabel) {
List<EdgeLabel> edgeLabels =
schemaDriver.edgeLabels(this.graphSpace, this.graph, this);
for (EdgeLabel edgeLabel : edgeLabels) {
if (edgeLabel.linkWithLabel(vertexLabel)) {
return true;
}
}
return false;
}
@Override
public VertexLabel vertexLabel(Id id) {
E.checkArgumentNotNull(id, "Vertex label id can't be null");
if (SchemaElement.OLAP_ID.equals(id)) {
return VertexLabel.OLAP_VL;
}
return schemaDriver.vertexLabel(this.graphSpace, this.graph, id, this);
}
@Override
public VertexLabel vertexLabel(String name) {
E.checkArgumentNotNull(name, "Vertex label name can't be null");
E.checkArgument(!name.isEmpty(), "Vertex label name can't be empty");
if (SchemaElement.OLAP.equals(name)) {
return VertexLabel.OLAP_VL;
}
return schemaDriver.vertexLabel(this.graphSpace, this.graph, name, this);
}
@Override
public EdgeLabel edgeLabel(Id id) {
return schemaDriver.edgeLabel(this.graphSpace, this.graph, id, this);
}
@Override
public EdgeLabel edgeLabel(String name) {
return schemaDriver.edgeLabel(this.graphSpace, this.graph, name, this);
}
@Override
public IndexLabel indexLabel(Id id) {
return schemaDriver.indexLabel(this.graphSpace, this.graph, id, this);
}
@Override
public Collection<IndexLabel> indexLabels() {
return schemaDriver.indexLabels(this.graphSpace, this.graph, this);
}
public IndexLabel indexLabel(String name) {
return schemaDriver.indexLabel(this.graphSpace, this.graph, name, this);
}
@Override
public String name() {
return String.join("-", this.graphSpace, this.graph);
}
}

View File

@ -0,0 +1,27 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.analyzer;
import java.util.Set;
public interface Analyzer {
public Set<String> segment(String text);
}

View File

@ -0,0 +1,102 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.analyzer;
import org.apache.hugegraph.exception.HugeException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class AnalyzerFactory {
private static Map<String, Class<? extends Analyzer>> analyzers;
static {
analyzers = new ConcurrentHashMap<>();
}
public static Analyzer analyzer(String name, String mode) {
name = name.toLowerCase();
switch (name) {
case "word":
return new WordAnalyzer(mode);
case "ansj":
return new AnsjAnalyzer(mode);
case "hanlp":
return new HanLPAnalyzer(mode);
case "smartcn":
return new SmartCNAnalyzer(mode);
case "jieba":
return new JiebaAnalyzer(mode);
case "jcseg":
return new JcsegAnalyzer(mode);
case "mmseg4j":
return new MMSeg4JAnalyzer(mode);
case "ikanalyzer":
return new IKAnalyzer(mode);
default:
return customizedAnalyzer(name, mode);
}
}
private static Analyzer customizedAnalyzer(String name, String mode) {
Class<? extends Analyzer> clazz = analyzers.get(name);
if (clazz == null) {
throw new HugeException("Not exists analyzer: %s", name);
}
assert Analyzer.class.isAssignableFrom(clazz);
try {
return clazz.getConstructor(String.class).newInstance(mode);
} catch (Exception e) {
throw new HugeException(
"Failed to construct analyzer '%s' with mode '%s'",
e, name, mode);
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public static void register(String name, String classPath) {
ClassLoader classLoader = AnalyzerFactory.class.getClassLoader();
Class<?> clazz;
try {
clazz = classLoader.loadClass(classPath);
} catch (Exception e) {
throw new HugeException("Load class path '%s' failed",
e, classPath);
}
// Check subclass
if (!Analyzer.class.isAssignableFrom(clazz)) {
throw new HugeException("Class '%s' is not a subclass of " +
"class Analyzer", classPath);
}
// Check exists
if (analyzers.containsKey(name)) {
throw new HugeException("Exists analyzer: %s(%s)",
name, analyzers.get(name).getName());
}
// Register class
analyzers.put(name, (Class) clazz);
}
}

View File

@ -0,0 +1,87 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.analyzer;
import java.util.List;
import java.util.Set;
import org.ansj.domain.Result;
import org.ansj.domain.Term;
import org.ansj.splitWord.analysis.BaseAnalysis;
import org.ansj.splitWord.analysis.IndexAnalysis;
import org.ansj.splitWord.analysis.NlpAnalysis;
import org.ansj.splitWord.analysis.ToAnalysis;
import org.apache.hugegraph.config.ConfigException;
import org.apache.hugegraph.util.InsertionOrderUtil;
import com.google.common.collect.ImmutableList;
/**
* Reference from https://my.oschina.net/apdplat/blog/412921
*/
public class AnsjAnalyzer implements Analyzer {
public static final List<String> SUPPORT_MODES = ImmutableList.of(
"BaseAnalysis",
"IndexAnalysis",
"ToAnalysis",
"NlpAnalysis"
);
private String analysis;
public AnsjAnalyzer(String mode) {
if (!SUPPORT_MODES.contains(mode)) {
throw new ConfigException(
"Unsupported segment mode '%s' for ansj analyzer, " +
"the available values are %s", mode, SUPPORT_MODES);
}
this.analysis = mode;
}
@Override
public Set<String> segment(String text) {
Result terms = null;
switch (this.analysis) {
case "BaseAnalysis":
terms = BaseAnalysis.parse(text);
break;
case "ToAnalysis":
terms = ToAnalysis.parse(text);
break;
case "NlpAnalysis":
terms = NlpAnalysis.parse(text);
break;
case "IndexAnalysis":
terms = IndexAnalysis.parse(text);
break;
default:
throw new AssertionError(String.format(
"Unsupported segment mode '%s'", this.analysis));
}
assert terms != null;
Set<String> result = InsertionOrderUtil.newSet();
for (Term term : terms) {
result.add(term.getName());
}
return result;
}
}

View File

@ -0,0 +1,108 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.analyzer;
import java.util.List;
import java.util.Set;
import com.google.common.collect.ImmutableList;
import com.hankcs.hanlp.seg.Dijkstra.DijkstraSegment;
import com.hankcs.hanlp.seg.NShort.NShortSegment;
import com.hankcs.hanlp.seg.Segment;
import com.hankcs.hanlp.seg.common.Term;
import com.hankcs.hanlp.tokenizer.IndexTokenizer;
import com.hankcs.hanlp.tokenizer.NLPTokenizer;
import com.hankcs.hanlp.tokenizer.SpeedTokenizer;
import com.hankcs.hanlp.tokenizer.StandardTokenizer;
import org.apache.hugegraph.config.ConfigException;
import org.apache.hugegraph.util.InsertionOrderUtil;
/**
* Reference from https://my.oschina.net/apdplat/blog/412921
*/
public class HanLPAnalyzer implements Analyzer {
public static final List<String> SUPPORT_MODES =
ImmutableList.<String>builder()
.add("standard")
.add("nlp")
.add("index")
.add("nShort")
.add("shortest")
.add("speed")
.build();
private static final Segment N_SHORT_SEGMENT =
new NShortSegment().enableCustomDictionary(false)
.enablePlaceRecognize(true)
.enableOrganizationRecognize(true);
private static final Segment DIJKSTRA_SEGMENT =
new DijkstraSegment().enableCustomDictionary(false)
.enablePlaceRecognize(true)
.enableOrganizationRecognize(true);
private String tokenizer;
public HanLPAnalyzer(String mode) {
if (!SUPPORT_MODES.contains(mode)) {
throw new ConfigException(
"Unsupported segment mode '%s' for hanlp analyzer, " +
"the available values are %s", mode, SUPPORT_MODES);
}
this.tokenizer = mode;
}
@Override
public Set<String> segment(String text) {
List<Term> terms = null;
switch (this.tokenizer) {
case "standard":
terms = StandardTokenizer.segment(text);
break;
case "nlp":
terms = NLPTokenizer.segment(text);
break;
case "index":
terms = IndexTokenizer.segment(text);
break;
case "nShort":
terms = N_SHORT_SEGMENT.seg(text);
break;
case "shortest":
terms = DIJKSTRA_SEGMENT.seg(text);
break;
case "speed":
terms = SpeedTokenizer.segment(text);
break;
default:
throw new AssertionError(String.format(
"Unsupported segment mode '%s'", this.tokenizer));
}
assert terms != null;
Set<String> result = InsertionOrderUtil.newSet();
for (Term term : terms) {
result.add(term.word);
}
return result;
}
}

View File

@ -0,0 +1,73 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.analyzer;
import com.google.common.collect.ImmutableList;
import org.apache.hugegraph.config.ConfigException;
import org.apache.hugegraph.exception.HugeException;
import org.apache.hugegraph.util.InsertionOrderUtil;
import org.wltea.analyzer.core.IKSegmenter;
import org.wltea.analyzer.core.Lexeme;
import java.io.StringReader;
import java.util.List;
import java.util.Set;
/**
* Reference from https://my.oschina.net/apdplat/blog/412921
*/
public class IKAnalyzer implements Analyzer {
public static final List<String> SUPPORT_MODES = ImmutableList.of(
"smart",
"max_word"
);
private boolean smartSegMode;
private final IKSegmenter ik;
public IKAnalyzer(String mode) {
if (!SUPPORT_MODES.contains(mode)) {
throw new ConfigException(
"Unsupported segment mode '%s' for ikanalyzer, " +
"the available values are %s", mode, SUPPORT_MODES);
}
this.smartSegMode = SUPPORT_MODES.get(0).equals(mode);
this.ik = new IKSegmenter(new StringReader(""),
this.smartSegMode);
}
@Override
public Set<String> segment(String text) {
Set<String> result = InsertionOrderUtil.newSet();
ik.reset(new StringReader(text));
try {
Lexeme word = null;
while ((word = ik.next()) != null) {
result.add(word.getLexemeText());
}
} catch (Exception e) {
throw new HugeException("IKAnalyzer segment text '%s' failed",
e, text);
}
return result;
}
}

View File

@ -0,0 +1,77 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.analyzer;
import java.io.StringReader;
import java.util.List;
import java.util.Set;
import org.apache.hugegraph.config.ConfigException;
import org.apache.hugegraph.exception.HugeException;
import org.apache.hugegraph.util.InsertionOrderUtil;
import org.lionsoul.jcseg.tokenizer.core.ADictionary;
import org.lionsoul.jcseg.tokenizer.core.DictionaryFactory;
import org.lionsoul.jcseg.tokenizer.core.ISegment;
import org.lionsoul.jcseg.tokenizer.core.IWord;
import org.lionsoul.jcseg.tokenizer.core.JcsegTaskConfig;
import org.lionsoul.jcseg.tokenizer.core.SegmentFactory;
import com.google.common.collect.ImmutableList;
/**
* Reference from https://my.oschina.net/apdplat/blog/412921
*/
public class JcsegAnalyzer implements Analyzer {
public static final List<String> SUPPORT_MODES = ImmutableList.of(
"Simple",
"Complex"
);
private static final JcsegTaskConfig CONFIG = new JcsegTaskConfig();
private static final ADictionary DIC =
DictionaryFactory.createDefaultDictionary(new JcsegTaskConfig());
private int segMode;
public JcsegAnalyzer(String mode) {
if (!SUPPORT_MODES.contains(mode)) {
throw new ConfigException(
"Unsupported segment mode '%s' for jcseg analyzer, " +
"the available values are %s", mode, SUPPORT_MODES);
}
this.segMode = SUPPORT_MODES.indexOf(mode) + 1;
}
@Override
public Set<String> segment(String text) {
Set<String> result = InsertionOrderUtil.newSet();
try {
Object[] args = new Object[]{new StringReader(text), CONFIG, DIC};
ISegment seg = SegmentFactory.createJcseg(this.segMode, args);
IWord word = null;
while ((word = seg.next()) != null) {
result.add(word.getValue());
}
} catch (Exception e) {
throw new HugeException("Jcseg segment text '%s' failed", e, text);
}
return result;
}
}

View File

@ -0,0 +1,63 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.analyzer;
import java.util.List;
import java.util.Set;
import org.apache.hugegraph.config.ConfigException;
import org.apache.hugegraph.util.InsertionOrderUtil;
import com.google.common.collect.ImmutableList;
import com.huaban.analysis.jieba.JiebaSegmenter;
import com.huaban.analysis.jieba.SegToken;
/**
* Reference from https://my.oschina.net/apdplat/blog/412921
*/
public class JiebaAnalyzer implements Analyzer {
public static final List<String> SUPPORT_MODES = ImmutableList.of(
"SEARCH",
"INDEX"
);
private static final JiebaSegmenter JIEBA_SEGMENTER = new JiebaSegmenter();
private JiebaSegmenter.SegMode segMode;
public JiebaAnalyzer(String mode) {
if (!SUPPORT_MODES.contains(mode)) {
throw new ConfigException(
"Unsupported segment mode '%s' for jieba analyzer, " +
"the available values are %s", mode, SUPPORT_MODES);
}
this.segMode = JiebaSegmenter.SegMode.valueOf(mode);
}
@Override
public Set<String> segment(String text) {
Set<String> result = InsertionOrderUtil.newSet();
for (SegToken token : JIEBA_SEGMENTER.process(text, this.segMode)) {
result.add(token.word);
}
return result;
}
}

View File

@ -0,0 +1,92 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.analyzer;
import java.io.StringReader;
import java.util.List;
import java.util.Set;
import org.apache.hugegraph.config.ConfigException;
import org.apache.hugegraph.util.InsertionOrderUtil;
import org.apache.hugegraph.exception.HugeException;
import com.chenlb.mmseg4j.ComplexSeg;
import com.chenlb.mmseg4j.Dictionary;
import com.chenlb.mmseg4j.MMSeg;
import com.chenlb.mmseg4j.MaxWordSeg;
import com.chenlb.mmseg4j.Seg;
import com.chenlb.mmseg4j.SimpleSeg;
import com.chenlb.mmseg4j.Word;
import com.google.common.collect.ImmutableList;
/**
* Reference from https://my.oschina.net/apdplat/blog/412921
*/
public class MMSeg4JAnalyzer implements Analyzer {
public static final List<String> SUPPORT_MODES = ImmutableList.of(
"Simple",
"Complex",
"MaxWord"
);
private static final Dictionary DIC = Dictionary.getInstance();
private Seg seg;
public MMSeg4JAnalyzer(String mode) {
if (!SUPPORT_MODES.contains(mode)) {
throw new ConfigException(
"Unsupported segment mode '%s' for mmseg4j analyzer, " +
"the available values are %s", mode, SUPPORT_MODES);
}
int index = SUPPORT_MODES.indexOf(mode);
switch (index) {
case 0:
this.seg = new SimpleSeg(DIC);
break;
case 1:
this.seg = new ComplexSeg(DIC);
break;
case 2:
this.seg = new MaxWordSeg(DIC);
break;
default:
throw new AssertionError(String.format(
"Unsupported segment mode '%s'", this.seg));
}
}
@Override
public Set<String> segment(String text) {
Set<String> result = InsertionOrderUtil.newSet();
MMSeg mmSeg = new MMSeg(new StringReader(text), this.seg);
try {
Word word = null;
while ((word = mmSeg.next()) != null) {
result.add(word.getString());
}
} catch (Exception e) {
throw new HugeException("MMSeg4j segment text '%s' failed",
e, text);
}
return result;
}
}

View File

@ -0,0 +1,66 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.analyzer;
import java.io.Reader;
import java.io.StringReader;
import java.util.List;
import java.util.Set;
import org.apache.hugegraph.util.InsertionOrderUtil;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.cn.smart.SmartChineseAnalyzer;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.hugegraph.exception.HugeException;
import com.google.common.collect.ImmutableList;
/**
* Reference from https://my.oschina.net/apdplat/blog/412921
*/
public class SmartCNAnalyzer implements Analyzer {
public static final List<String> SUPPORT_MODES = ImmutableList.of();
private static final SmartChineseAnalyzer ANALYZER =
new SmartChineseAnalyzer();
public SmartCNAnalyzer(String mode) {
// pass
}
@Override
public Set<String> segment(String text) {
Set<String> result = InsertionOrderUtil.newSet();
Reader reader = new StringReader(text);
try (TokenStream tokenStream = ANALYZER.tokenStream("text", reader)) {
tokenStream.reset();
CharTermAttribute term = null;
while (tokenStream.incrementToken()) {
term = tokenStream.getAttribute(CharTermAttribute.class);
result.add(term.toString());
}
} catch (Exception e) {
throw new HugeException("SmartCN segment text '%s' failed",
e, text);
}
return result;
}
}

View File

@ -0,0 +1,74 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.analyzer;
import java.util.List;
import java.util.Set;
import org.apache.hugegraph.config.ConfigException;
import org.apache.hugegraph.util.InsertionOrderUtil;
import org.apdplat.word.WordSegmenter;
import org.apdplat.word.segmentation.SegmentationAlgorithm;
import org.apdplat.word.segmentation.Word;
import com.google.common.collect.ImmutableList;
/**
* Reference from https://my.oschina.net/apdplat/blog/412921
*/
public class WordAnalyzer implements Analyzer {
public static final List<String> SUPPORT_MODES =
ImmutableList.<String>builder()
.add("MaximumMatching")
.add("ReverseMaximumMatching")
.add("MinimumMatching")
.add("ReverseMinimumMatching")
.add("BidirectionalMaximumMatching")
.add("BidirectionalMinimumMatching")
.add("BidirectionalMaximumMinimumMatching")
.add("FullSegmentation")
.add("MinimalWordCount")
.add("MaxNgramScore")
.add("PureEnglish")
.build();
private SegmentationAlgorithm algorithm;
public WordAnalyzer(String mode) {
try {
this.algorithm = SegmentationAlgorithm.valueOf(mode);
} catch (Exception e) {
throw new ConfigException(
"Unsupported segment mode '%s' for word analyzer, " +
"the available values are %s", e, mode, SUPPORT_MODES);
}
}
@Override
public Set<String> segment(String text) {
Set<String> result = InsertionOrderUtil.newSet();
List<Word> words = WordSegmenter.segWithStopWords(text, this.algorithm);
for (Word word : words) {
result.add(word.getText());
}
return result;
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.auth;
public interface AuthConstant {
/*
* Fields in token
*/
String TOKEN_USER_NAME = "user_name";
String TOKEN_USER_ID = "user_id";
String TOKEN_USER_PASSWORD = "user_password";
}

View File

@ -0,0 +1,70 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.auth;
import org.apache.hugegraph.options.AuthOptions;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import jakarta.ws.rs.NotAuthorizedException;
import org.apache.hugegraph.config.HugeConfig;
import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Map;
public class TokenGenerator {
private final SecretKey key;
public TokenGenerator(HugeConfig config) {
String secretKey = config.get(AuthOptions.AUTH_TOKEN_SECRET);
this.key = Keys.hmacShaKeyFor(secretKey.getBytes(StandardCharsets.UTF_8));
}
public TokenGenerator(String secretKey) {
this.key = Keys.hmacShaKeyFor(secretKey.getBytes(StandardCharsets.UTF_8));
}
public String create(Map<String, ?> payload, long expire) {
return Jwts.builder()
.setClaims(payload)
.setExpiration(new Date(System.currentTimeMillis() + expire))
.signWith(this.key, SignatureAlgorithm.HS256)
.compact();
}
public Claims verify(String token) {
try {
Jws<Claims> claimsJws = Jwts.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(token);
return claimsJws.getBody();
} catch (ExpiredJwtException e) {
throw new NotAuthorizedException("The token is expired", e);
} catch (JwtException e) {
throw new NotAuthorizedException("Invalid token", e);
}
}
}

View File

@ -0,0 +1,69 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.backend;
import java.util.Arrays;
import org.apache.hugegraph.util.Bytes;
import org.apache.hugegraph.util.StringEncoding;
public class BackendColumn implements Comparable<BackendColumn> {
public byte[] name;
public byte[] value;
public static BackendColumn of(byte[] name, byte[] value) {
BackendColumn col = new BackendColumn();
col.name = name;
col.value = value;
return col;
}
@Override
public String toString() {
return String.format("%s=%s",
StringEncoding.decode(name),
StringEncoding.decode(value));
}
@Override
public int compareTo(BackendColumn other) {
if (other == null) {
return 1;
}
return Bytes.compare(this.name, other.name);
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof BackendColumn)) {
return false;
}
BackendColumn other = (BackendColumn) obj;
return Bytes.equals(this.name, other.name) &&
Bytes.equals(this.value, other.value);
}
@Override
public int hashCode() {
return Arrays.hashCode(this.name) | Arrays.hashCode(this.value);
}
}

View File

@ -0,0 +1,103 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.backend;
import org.apache.hugegraph.id.Id;
import org.apache.hugegraph.util.Bytes;
import org.apache.hugegraph.util.E;
import java.nio.ByteBuffer;
import java.util.Arrays;
public final class BinaryId implements Id {
private final byte[] bytes;
private final Id id;
public BinaryId(byte[] bytes, Id id) {
this.bytes = bytes;
this.id = id;
}
public Id origin() {
return this.id;
}
@Override
public IdType type() {
return IdType.UNKNOWN;
}
@Override
public Object asObject() {
return ByteBuffer.wrap(this.bytes);
}
@Override
public String asString() {
throw new UnsupportedOperationException();
}
@Override
public long asLong() {
throw new UnsupportedOperationException();
}
@Override
public int compareTo(Id other) {
return Bytes.compare(this.bytes, other.asBytes());
}
@Override
public byte[] asBytes() {
return this.bytes;
}
public byte[] asBytes(int offset) {
E.checkArgument(offset < this.bytes.length,
"Invalid offset %s, must be < length %s",
offset, this.bytes.length);
return Arrays.copyOfRange(this.bytes, offset, this.bytes.length);
}
@Override
public int length() {
return this.bytes.length;
}
@Override
public int hashCode() {
return ByteBuffer.wrap(this.bytes).hashCode();
}
@Override
public boolean equals(Object other) {
if (!(other instanceof BinaryId)) {
return false;
}
return Arrays.equals(this.bytes, ((BinaryId) other).bytes);
}
@Override
public String toString() {
return "0x" + Bytes.toHex(this.bytes);
}
}

View File

@ -0,0 +1,71 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.backend;
/**
* Shard is used for backend storage (like cassandra, hbase) scanning
* operations. Each shard represents a range of tokens for a node.
* Reading data from a given shard does not cross multiple nodes.
*/
public class Shard {
// token range start
private String start;
// token range end
private String end;
// partitions count in this range
private long length;
public Shard(String start, String end, long length) {
this.start = start;
this.end = end;
this.length = length;
}
public String start() {
return this.start;
}
public void start(String start) {
this.start = start;
}
public String end() {
return this.end;
}
public void end(String end) {
this.end = end;
}
public long length() {
return this.length;
}
public void length(long length) {
this.length = length;
}
@Override
public String toString() {
return String.format("Shard{start=%s, end=%s, length=%s}",
this.start, this.end, this.length);
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.exception;
public class BackendException extends HugeException {
private static final long serialVersionUID = -1947589125372576298L;
public BackendException(String message) {
super(message);
}
public BackendException(String message, Throwable cause) {
super(message, cause);
}
public BackendException(String message, Object... args) {
super(message, args);
}
public BackendException(String message, Throwable cause, Object... args) {
super(message, cause, args);
}
public BackendException(Throwable cause) {
this("Exception in backend", cause);
}
public static final void check(boolean expression,
String message, Object... args)
throws BackendException {
if (!expression) {
throw new BackendException(message, args);
}
}
}

View File

@ -0,0 +1,27 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.exception;
public interface ErrorCodeProvider {
public String format(Object... args);
public String with(String message);
}

View File

@ -0,0 +1,70 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.exception;
public class HugeException extends RuntimeException {
private static final long serialVersionUID = -8711375282196157058L;
public HugeException(String message) {
super(message);
}
public HugeException(ErrorCodeProvider code, String message) {
super(code.with(message));
}
public HugeException(String message, Throwable cause) {
super(message, cause);
}
public HugeException(ErrorCodeProvider code, String message, Throwable cause) {
super(code.with(message), cause);
}
public HugeException(String message, Object... args) {
super(String.format(message, args));
}
public HugeException(ErrorCodeProvider code, Object... args) {
super(code.format(args));
}
public HugeException(String message, Throwable cause, Object... args) {
super(String.format(message, args), cause);
}
public HugeException(ErrorCodeProvider code, Throwable cause, Object... args) {
super(code.format(args), cause);
}
public Throwable rootCause() {
return rootCause(this);
}
public static Throwable rootCause(Throwable e) {
Throwable cause = e;
while (cause.getCause() != null) {
cause = cause.getCause();
}
return cause;
}
}

View File

@ -0,0 +1,33 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.exception;
public class LimitExceedException extends HugeException {
private static final long serialVersionUID = 7384276720045597709L;
public LimitExceedException(String message) {
super(message);
}
public LimitExceedException(String message, Object... args) {
super(message, args);
}
}

View File

@ -0,0 +1,33 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.exception;
public class NotAllowException extends HugeException {
private static final long serialVersionUID = -1407924451828873200L;
public NotAllowException(String message) {
super(message);
}
public NotAllowException(String message, Object... args) {
super(message, args);
}
}

View File

@ -0,0 +1,37 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.exception;
public class NotFoundException extends HugeException {
private static final long serialVersionUID = -5912665926327173032L;
public NotFoundException(String message) {
super(message);
}
public NotFoundException(String message, Object... args) {
super(message, args);
}
public NotFoundException(String message, Throwable cause, Object... args) {
super(message, cause, args);
}
}

View File

@ -0,0 +1,34 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.exception;
public class NotSupportException extends HugeException {
private static final long serialVersionUID = -2914329541122906234L;
private static final String PREFIX = "Not support ";
public NotSupportException(String message) {
super(PREFIX + message);
}
public NotSupportException(String message, Object... args) {
super(PREFIX + message, args);
}
}

View File

@ -0,0 +1,350 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.id;
import org.apache.hugegraph.perf.PerfUtil.Watched;
import org.apache.hugegraph.testutil.Assert;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.exception.NotFoundException;
import org.apache.hugegraph.type.HugeType;
import org.apache.hugegraph.type.define.Directions;
import org.apache.hugegraph.type.define.HugeKeys;
import org.apache.hugegraph.util.StringEncoding;
/**
* Class used to format and parse id of edge, the edge id consists of:
* EdgeId = { source-vertex-id > direction > parentEdgeLabelId > subEdgeLabelId
* >sortKeys > target-vertex-id }
* NOTE:
* 1. for edges with edgeLabel-type=NORMAL,edgelabelId=parentEdgeLabelId=subEdgeLabelId,
* for edges with edgeLabel type=PARENTedgelabelId = subEdgeLabelId ,
* parentEdgeLabelId = edgelabelId.fatherId
*
* 2.if we use `entry.type()` which is IN or OUT as a part of id,
* an edge's id will be different due to different directions (belongs
* to 2 owner vertex)
*/
public class EdgeId implements Id {
public static final HugeKeys[] KEYS = new HugeKeys[] {
HugeKeys.OWNER_VERTEX,
HugeKeys.DIRECTION,
HugeKeys.LABEL,
HugeKeys.SUB_LABEL,
HugeKeys.SORT_VALUES,
HugeKeys.OTHER_VERTEX
};
private final Id ownerVertexId;
private final Directions direction;
private final Id edgeLabelId;
private final Id subLabelId;
private final String sortValues;
private final Id otherVertexId;
private final boolean directed;
private String cache;
public EdgeId(Id ownerVertexId, Directions direction, Id edgeLabelId,
Id subLabelId, String sortValues,
Id otherVertexId) {
this(ownerVertexId, direction, edgeLabelId,
subLabelId, sortValues, otherVertexId, false);
}
public EdgeId(Id ownerVertexId, Directions direction, Id edgeLabelId,
Id subLabelId, String sortValues,
Id otherVertexId, boolean directed) {
this.ownerVertexId = ownerVertexId;
this.direction = direction;
this.edgeLabelId = edgeLabelId;
this.sortValues = sortValues;
this.subLabelId = subLabelId;
this.otherVertexId = otherVertexId;
this.directed = directed;
this.cache = null;
}
@Watched
public EdgeId switchDirection() {
Directions direction = this.direction.opposite();
return new EdgeId(this.otherVertexId, direction, this.edgeLabelId,
this.subLabelId, this.sortValues, this.ownerVertexId,
this.directed);
}
public EdgeId directed(boolean directed) {
return new EdgeId(this.ownerVertexId, this.direction, this.edgeLabelId,
this.subLabelId, this.sortValues, this.otherVertexId, directed);
}
private Id sourceVertexId() {
return this.direction == Directions.OUT ?
this.ownerVertexId :
this.otherVertexId;
}
private Id targetVertexId() {
return this.direction == Directions.OUT ?
this.otherVertexId :
this.ownerVertexId;
}
public Id subLabelId(){
return this.subLabelId;
}
public Id ownerVertexId() {
return this.ownerVertexId;
}
public Id edgeLabelId() {
return this.edgeLabelId;
}
public Directions direction() {
return this.direction;
}
public byte directionCode() {
return directionToCode(this.direction);
}
public String sortValues() {
return this.sortValues;
}
public Id otherVertexId() {
return this.otherVertexId;
}
@Override
public Object asObject() {
return this.asString();
}
@Override
public String asString() {
if (this.cache != null) {
return this.cache;
}
if (this.directed) {
this.cache = SplicingIdGenerator.concat(
IdUtil.writeString(this.ownerVertexId),
this.direction.type().string(),
IdUtil.writeLong(this.edgeLabelId),
IdUtil.writeLong(this.subLabelId),
this.sortValues,
IdUtil.writeString(this.otherVertexId));
} else {
this.cache = SplicingIdGenerator.concat(
IdUtil.writeString(this.sourceVertexId()),
IdUtil.writeLong(this.edgeLabelId),
IdUtil.writeLong(this.subLabelId),
this.sortValues,
IdUtil.writeString(this.targetVertexId()));
}
return this.cache;
}
@Override
public long asLong() {
throw new UnsupportedOperationException();
}
@Override
public byte[] asBytes() {
return StringEncoding.encode(this.asString());
}
@Override
public int length() {
return this.asString().length();
}
@Override
public IdType type() {
return IdType.EDGE;
}
@Override
public int compareTo(Id other) {
return this.asString().compareTo(other.asString());
}
@Override
public int hashCode() {
if (this.directed) {
return this.ownerVertexId.hashCode() ^
this.direction.hashCode() ^
this.edgeLabelId.hashCode() ^
this.subLabelId.hashCode() ^
this.sortValues.hashCode() ^
this.otherVertexId.hashCode();
} else {
return this.sourceVertexId().hashCode() ^
this.edgeLabelId.hashCode() ^
this.subLabelId.hashCode() ^
this.sortValues.hashCode() ^
this.targetVertexId().hashCode();
}
}
@Override
public boolean equals(Object object) {
if (!(object instanceof EdgeId)) {
return false;
}
EdgeId other = (EdgeId) object;
if (this.directed) {
return this.ownerVertexId.equals(other.ownerVertexId) &&
this.direction == other.direction &&
this.edgeLabelId.equals(other.edgeLabelId) &&
this.sortValues.equals(other.sortValues) &&
this.subLabelId.equals(other.subLabelId) &&
this.otherVertexId.equals(other.otherVertexId);
} else {
return this.sourceVertexId().equals(other.sourceVertexId()) &&
this.edgeLabelId.equals(other.edgeLabelId) &&
this.sortValues.equals(other.sortValues) &&
this.subLabelId.equals(other.subLabelId) &&
this.targetVertexId().equals(other.targetVertexId());
}
}
@Override
public String toString() {
return this.asString();
}
public static byte directionToCode(Directions direction) {
return direction.type().code();
}
public static Directions directionFromCode(byte code) {
return (code == HugeType.EDGE_OUT.code()) ? Directions.OUT : Directions.IN;
}
public static boolean isOutDirectionFromCode(byte code) {
return code == HugeType.EDGE_OUT.code();
}
public static EdgeId parse(String id) throws NotFoundException {
return parse(id, false);
}
public static EdgeId parse(String id, boolean returnNullIfError)
throws NotFoundException {
String[] idParts = SplicingIdGenerator.split(id);
if (!(idParts.length == 5 || idParts.length == 6)) {
if (returnNullIfError) {
return null;
}
throw new NotFoundException("Edge id must be formatted as 5~6 " +
"parts, but got %s parts: '%s'",
idParts.length, id);
}
try {
if (idParts.length == 5) {
Id ownerVertexId = IdUtil.readString(idParts[0]);
Id edgeLabelId = IdUtil.readLong(idParts[1]);
Id subLabelId = IdUtil.readLong(idParts[2]);
String sortValues = idParts[3];
Id otherVertexId = IdUtil.readString(idParts[4]);
return new EdgeId(ownerVertexId, Directions.OUT, edgeLabelId,
subLabelId, sortValues, otherVertexId);
} else {
assert idParts.length == 6;
Id ownerVertexId = IdUtil.readString(idParts[0]);
HugeType direction = HugeType.fromString(idParts[1]);
Id edgeLabelId = IdUtil.readLong(idParts[2]);
Id subLabelId = IdUtil.readLong(idParts[3]);
String sortValues = idParts[4];
Id otherVertexId = IdUtil.readString(idParts[5]);
return new EdgeId(ownerVertexId, Directions.convert(direction),
edgeLabelId, subLabelId,
sortValues, otherVertexId);
}
} catch (Throwable e) {
if (returnNullIfError) {
return null;
}
throw new NotFoundException("Invalid format of edge id '%s'",
e, id);
}
}
public static Id parseStoredString(String id) {
String[] idParts = split(id);
E.checkArgument(idParts.length == 5, "Invalid id format: %s", id);
Id ownerVertexId = IdUtil.readStoredString(idParts[0]);
Id edgeLabelId = IdGenerator.ofStoredString(idParts[1], IdType.LONG);
Id subLabelId = IdGenerator.ofStoredString(idParts[2], IdType.LONG);
String sortValues = idParts[3];
Id otherVertexId = IdUtil.readStoredString(idParts[4]);
return new EdgeId(ownerVertexId, Directions.OUT, edgeLabelId,
subLabelId, sortValues, otherVertexId);
}
public static String asStoredString(Id id) {
EdgeId eid = (EdgeId) id;
return SplicingIdGenerator.concat(
IdUtil.writeStoredString(eid.sourceVertexId()),
IdGenerator.asStoredString(eid.edgeLabelId()),
IdGenerator.asStoredString(eid.subLabelId()),
eid.sortValues(),
IdUtil.writeStoredString(eid.targetVertexId()));
}
public static String concat(String... ids) {
return SplicingIdGenerator.concat(ids);
}
public static String[] split(Id id) {
return EdgeId.split(id.asString());
}
public static String[] split(String id) {
return SplicingIdGenerator.split(id);
}
public static void main(String[] args) {
EdgeId edgeId1 = new EdgeId(IdGenerator.of("1:marko"), Directions.OUT,
IdGenerator.of(1),
IdGenerator.of(1), "",
IdGenerator.of("1:josh"));
EdgeId edgeId2 = new EdgeId(IdGenerator.of("1:marko"), Directions.OUT,
IdGenerator.of(1),
IdGenerator.of(1), "",
IdGenerator.of("1:josh"));
EdgeId edgeId3 = new EdgeId(IdGenerator.of("1:josh"), Directions.IN,
IdGenerator.of(1),
IdGenerator.of(1), "",
IdGenerator.of("1:marko"));
Assert.assertTrue(edgeId1.equals(edgeId2));
Assert.assertTrue(edgeId2.equals(edgeId1));
Assert.assertTrue(edgeId1.equals(edgeId3));
Assert.assertTrue(edgeId3.equals(edgeId1));
}
}

View File

@ -0,0 +1,90 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.id;
import java.io.Serializable;
import org.apache.hugegraph.util.E;
public interface Id extends Comparable<Id>, Serializable {
public static final int UUID_LENGTH = 16;
public Object asObject();
public String asString();
public long asLong();
public byte[] asBytes();
public int length();
public IdType type();
public default boolean number() {
return this.type() == IdType.LONG;
}
public default boolean uuid() {
return this.type() == IdType.UUID;
}
public default boolean string() {
return this.type() == IdType.STRING;
}
public default boolean edge() {
return this.type() == IdType.EDGE;
}
public enum IdType {
UNKNOWN,
LONG,
UUID,
STRING,
EDGE;
public char prefix() {
if (this == UNKNOWN) {
return 'N';
}
return this.name().charAt(0);
}
public static IdType valueOfPrefix(String id) {
E.checkArgument(id != null && id.length() > 0,
"Invalid id '%s'", id);
switch (id.charAt(0)) {
case 'L':
return IdType.LONG;
case 'U':
return IdType.UUID;
case 'S':
return IdType.STRING;
case 'E':
return IdType.EDGE;
default:
return IdType.UNKNOWN;
}
}
}
}

View File

@ -0,0 +1,465 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.id;
import org.apache.hugegraph.serializer.BytesBuffer;
import org.apache.hugegraph.structure.BaseVertex;
import org.apache.hugegraph.util.StringEncoding;
import com.google.common.primitives.Longs;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.LongEncoding;
import org.apache.hugegraph.util.NumericUtil;
import java.nio.charset.Charset;
import java.util.Objects;
import java.util.UUID;
public abstract class IdGenerator {
public static final Id ZERO = IdGenerator.of(0L);
public abstract Id generate(BaseVertex vertex);
public final static Id of(String id) {
return new StringId(id);
}
public final static Id of(UUID id) {
return new UuidId(id);
}
public final static Id of(String id, boolean uuid) {
return uuid ? new UuidId(id) : new StringId(id);
}
public final static Id of(long id) {
return new LongId(id);
}
public static Id of(Object id) {
if (id instanceof Id) {
return (Id) id;
} else if (id instanceof String) {
return of((String) id);
} else if (id instanceof Number) {
return of(((Number) id).longValue());
} else if (id instanceof UUID) {
return of((UUID) id);
}
return new ObjectId(id);
}
public final static Id of(byte[] bytes, Id.IdType type) {
switch (type) {
case LONG:
return new LongId(bytes);
case UUID:
return new UuidId(bytes);
case STRING:
return new StringId(bytes);
default:
throw new AssertionError("Invalid id type " + type);
}
}
public final static Id ofStoredString(String id, Id.IdType type) {
switch (type) {
case LONG:
return of(LongEncoding.decodeSignedB64(id));
case UUID:
byte[] bytes = StringEncoding.decodeBase64(id);
return of(bytes, Id.IdType.UUID);
case STRING:
return of(id);
default:
throw new AssertionError("Invalid id type " + type);
}
}
public final static String asStoredString(Id id) {
switch (id.type()) {
case LONG:
return LongEncoding.encodeSignedB64(id.asLong());
case UUID:
return StringEncoding.encodeBase64(id.asBytes());
case STRING:
return id.asString();
default:
throw new AssertionError("Invalid id type " + id.type());
}
}
public final static Id.IdType idType(Id id) {
if (id instanceof LongId) {
return Id.IdType.LONG;
}
if (id instanceof UuidId) {
return Id.IdType.UUID;
}
if (id instanceof StringId) {
return Id.IdType.STRING;
}
if (id instanceof EdgeId) {
return Id.IdType.EDGE;
}
return Id.IdType.UNKNOWN;
}
private final static int compareType(Id id1, Id id2) {
return idType(id1).ordinal() - idType(id2).ordinal();
}
/****************************** id defines ******************************/
public static final class StringId implements Id {
private final String id;
private static final Charset CHARSET = Charset.forName("UTF-8");
public StringId(String id) {
E.checkArgument(!id.isEmpty(), "The id can't be empty");
this.id = id;
}
public StringId(byte[] bytes) {
this.id = StringEncoding.decode(bytes);
}
@Override
public IdType type() {
return IdType.STRING;
}
@Override
public Object asObject() {
return this.id;
}
@Override
public String asString() {
return this.id;
}
@Override
public long asLong() {
return Long.parseLong(this.id);
}
@Override
public byte[] asBytes() {
return this.id.getBytes(CHARSET);
}
@Override
public int length() {
return this.id.length();
}
@Override
public int compareTo(Id other) {
int cmp = compareType(this, other);
if (cmp != 0) {
return cmp;
}
return this.id.compareTo(other.asString());
}
@Override
public int hashCode() {
return this.id.hashCode();
}
@Override
public boolean equals(Object other) {
if (!(other instanceof StringId)) {
return false;
}
return this.id.equals(((StringId) other).id);
}
@Override
public String toString() {
return this.id;
}
}
public static final class LongId extends Number implements Id {
private static final long serialVersionUID = -7732461469037400190L;
private final long id;
public LongId(long id) {
this.id = id;
}
public LongId(byte[] bytes) {
this.id = NumericUtil.bytesToLong(bytes);
}
@Override
public IdType type() {
return IdType.LONG;
}
@Override
public Object asObject() {
return this.id;
}
@Override
public String asString() {
// TODO: encode with base64
return Long.toString(this.id);
}
@Override
public long asLong() {
return this.id;
}
@Override
public byte[] asBytes() {
return Longs.toByteArray(this.id);
// return NumericUtil.longToBytes(this.id);
}
@Override
public int length() {
return Long.BYTES;
}
@Override
public int compareTo(Id other) {
int cmp = compareType(this, other);
if (cmp != 0) {
return cmp;
}
return Long.compare(this.id, other.asLong());
}
@Override
public int hashCode() {
return Long.hashCode(this.id);
}
@Override
public boolean equals(Object other) {
if (!(other instanceof Number)) {
if (idDigitalObject(other)) {
return this.id == (long) Double.parseDouble(other.toString());
}
return false;
}
return this.id == ((Number) other).longValue();
}
private static boolean idDigitalObject(Object object) {
String string = object.toString();
for (int i = string.length(); --i >= 0; ) {
char c = string.charAt(i);
if (!Character.isDigit(c) &&
'.' != c) {
return false;
}
}
return true;
}
@Override
public String toString() {
return String.valueOf(this.id);
}
@Override
public int intValue() {
return (int) this.id;
}
@Override
public long longValue() {
return this.id;
}
@Override
public float floatValue() {
return this.id;
}
@Override
public double doubleValue() {
return this.id;
}
}
public static final class UuidId implements Id {
private final UUID uuid;
public UuidId(String string) {
this(StringEncoding.uuid(string));
}
public UuidId(byte[] bytes) {
this(fromBytes(bytes));
}
public UuidId(UUID uuid) {
E.checkArgument(uuid != null, "The uuid can't be null");
this.uuid = uuid;
}
@Override
public IdType type() {
return IdType.UUID;
}
@Override
public Object asObject() {
return this.uuid;
}
@Override
public String asString() {
return this.uuid.toString();
}
@Override
public long asLong() {
throw new UnsupportedOperationException();
}
@Override
public byte[] asBytes() {
BytesBuffer buffer = BytesBuffer.allocate(16);
buffer.writeLong(this.uuid.getMostSignificantBits());
buffer.writeLong(this.uuid.getLeastSignificantBits());
return buffer.bytes();
}
private static UUID fromBytes(byte[] bytes) {
E.checkArgument(bytes != null, "The UUID can't be null");
BytesBuffer buffer = BytesBuffer.wrap(bytes);
long high = buffer.readLong();
long low = buffer.readLong();
return new UUID(high, low);
}
@Override
public int length() {
return UUID_LENGTH;
}
@Override
public int compareTo(Id other) {
E.checkNotNull(other, "compare id");
int cmp = compareType(this, other);
if (cmp != 0) {
return cmp;
}
return this.uuid.compareTo(((UuidId) other).uuid);
}
@Override
public int hashCode() {
return this.uuid.hashCode();
}
@Override
public boolean equals(Object other) {
if (!(other instanceof UuidId)) {
return false;
}
return this.uuid.equals(((UuidId) other).uuid);
}
@Override
public String toString() {
return this.uuid.toString();
}
}
/**
* This class is just used by backend store for wrapper object as Id
*/
public static final class ObjectId implements Id {
private final Object object;
public ObjectId(Object object) {
E.checkNotNull(object, "object");
this.object = object;
}
@Override
public IdType type() {
return IdType.UNKNOWN;
}
@Override
public Object asObject() {
return this.object;
}
@Override
public String asString() {
throw new UnsupportedOperationException();
}
@Override
public long asLong() {
throw new UnsupportedOperationException();
}
@Override
public byte[] asBytes() {
throw new UnsupportedOperationException();
}
@Override
public int length() {
throw new UnsupportedOperationException();
}
@Override
public int compareTo(Id o) {
throw new UnsupportedOperationException();
}
@Override
public int hashCode() {
return this.object.hashCode();
}
@Override
public boolean equals(Object other) {
if (!(other instanceof ObjectId)) {
return false;
}
return Objects.equals(this.object, ((ObjectId) other).object);
}
@Override
public String toString() {
return this.object.toString();
}
}
}

View File

@ -0,0 +1,162 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.id;
import java.nio.ByteBuffer;
import org.apache.commons.lang3.StringUtils;
import org.apache.hugegraph.serializer.BytesBuffer;
public final class IdUtil {
public static String writeStoredString(Id id) {
String idString;
switch (id.type()) {
case LONG:
case STRING:
case UUID:
idString = IdGenerator.asStoredString(id);
break;
case EDGE:
idString = EdgeId.asStoredString(id);
break;
default:
throw new AssertionError("Invalid id type " + id.type());
}
return id.type().prefix() + idString;
}
public static Id readStoredString(String id) {
Id.IdType type = Id.IdType.valueOfPrefix(id);
String idContent = id.substring(1);
switch (type) {
case LONG:
case STRING:
case UUID:
return IdGenerator.ofStoredString(idContent, type);
case EDGE:
return EdgeId.parseStoredString(idContent);
default:
throw new IllegalArgumentException("Invalid id: " + id);
}
}
public static Object writeBinString(Id id) {
int len = id.edge() ? BytesBuffer.BUF_EDGE_ID : id.length() + 1;
BytesBuffer buffer = BytesBuffer.allocate(len).writeId(id);
buffer.forReadWritten();
return buffer.asByteBuffer();
}
public static Id readBinString(Object id) {
BytesBuffer buffer = BytesBuffer.wrap((ByteBuffer) id);
return buffer.readId();
}
public static byte[] asBytes(Id id) {
int len = id.edge() ? BytesBuffer.BUF_EDGE_ID : id.length() + 1;
BytesBuffer buffer = BytesBuffer.allocate(len).writeId(id);
return buffer.bytes();
}
public static Id fromBytes(byte[] bytes) {
BytesBuffer buffer = BytesBuffer.wrap(bytes);
return buffer.readId();
}
public static String writeString(Id id) {
String idString = id.asString();
StringBuilder sb = new StringBuilder(1 + idString.length());
sb.append(id.type().prefix()).append(idString);
return sb.toString();
}
public static Id readString(String id) {
Id.IdType type = Id.IdType.valueOfPrefix(id);
String idContent = id.substring(1);
switch (type) {
case LONG:
return IdGenerator.of(Long.parseLong(idContent));
case STRING:
case UUID:
return IdGenerator.of(idContent, type == Id.IdType.UUID);
case EDGE:
return EdgeId.parse(idContent);
default:
throw new IllegalArgumentException("Invalid id: " + id);
}
}
public static String writeLong(Id id) {
return String.valueOf(id.asLong());
}
public static Id readLong(String id) {
return IdGenerator.of(Long.parseLong(id));
}
public static String escape(char splitor, char escape, String... values) {
int length = values.length + 4;
for (String value : values) {
length += value.length();
}
StringBuilder escaped = new StringBuilder(length);
// Do escape for every item in values
for (String value : values) {
if (escaped.length() > 0) {
escaped.append(splitor);
}
if (value.indexOf(splitor) == -1) {
escaped.append(value);
continue;
}
// Do escape for current item
for (int i = 0, n = value.length(); i < n; i++) {
char ch = value.charAt(i);
if (ch == splitor) {
escaped.append(escape);
}
escaped.append(ch);
}
}
return escaped.toString();
}
public static String[] unescape(String id, String splitor, String escape) {
/*
* Note that the `splitor`/`escape` maybe special characters in regular
* expressions, but this is a frequently called method, for faster
* execution, we forbid the use of special characters as delimiter
* or escape sign.
* The `limit` param -1 in split method can ensure empty string be
* splited to a part.
*/
String[] parts = id.split("(?<!" + escape + ")" + splitor, -1);
for (int i = 0; i < parts.length; i++) {
parts[i] = StringUtils.replace(parts[i], escape + splitor,
splitor);
}
return parts;
}
}

View File

@ -0,0 +1,150 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.id;
import java.util.Arrays;
import java.util.List;
import org.apache.hugegraph.backend.BinaryId;
import org.apache.hugegraph.serializer.BytesBuffer;
import org.apache.hugegraph.structure.BaseVertex;
public class SplicingIdGenerator extends IdGenerator {
private static volatile SplicingIdGenerator instance;
public static SplicingIdGenerator instance() {
if (instance == null) {
synchronized (SplicingIdGenerator.class) {
if (instance == null) {
instance = new SplicingIdGenerator();
}
}
}
return instance;
}
/*
* The following defines can't be java regex special characters:
* "\^$.|?*+()[{"
* See: http://www.regular-expressions.info/characters.html
*/
private static final char ESCAPE = '`';
private static final char IDS_SPLITOR = '>';
private static final char ID_SPLITOR = ':';
private static final char NAME_SPLITOR = '!';
public static final String ESCAPE_STR = String.valueOf(ESCAPE);
public static final String IDS_SPLITOR_STR = String.valueOf(IDS_SPLITOR);
public static final String ID_SPLITOR_STR = String.valueOf(ID_SPLITOR);
/****************************** id generate ******************************/
/**
* Generate a string id of HugeVertex from Vertex name
*/
@Override
public Id generate(BaseVertex vertex) {
/*
* Hash for row-key which will be evenly distributed.
* We can also use LongEncoding.encode() to encode the int/long hash
* if needed.
* id = String.format("%s%s%s", HashUtil.hash(id), ID_SPLITOR, id);
*/
// TODO: use binary Id with binary fields instead of string id
return splicing(vertex.schemaLabel().id().asString(), vertex.name());
}
/**
* Concat multiple ids into one composite id with IDS_SPLITOR
* @param ids the string id values to be concatted
* @return concatted string value
*/
public static String concat(String... ids) {
// NOTE: must support string id when using this method
return IdUtil.escape(IDS_SPLITOR, ESCAPE, ids);
}
/**
* Split a composite id into multiple ids with IDS_SPLITOR
* @param ids the string id value to be splitted
* @return splitted string values
*/
public static String[] split(String ids) {
return IdUtil.unescape(ids, IDS_SPLITOR_STR, ESCAPE_STR);
}
/**
* Concat property values with NAME_SPLITOR
* @param values the property values to be concatted
* @return concatted string value
*/
public static String concatValues(List<?> values) {
// Convert the object list to string array
int valuesSize = values.size();
String[] parts = new String[valuesSize];
for (int i = 0; i < valuesSize; i++) {
parts[i] = values.get(i).toString();
}
return IdUtil.escape(NAME_SPLITOR, ESCAPE, parts);
}
/**
* Concat property values with NAME_SPLITOR
* @param values the property values to be concatted
* @return concatted string value
*/
public static String concatValues(Object... values) {
return concatValues(Arrays.asList(values));
}
/**
* Concat multiple parts into a single id with ID_SPLITOR
* @param parts the string id values to be spliced
* @return spliced id object
*/
public static Id splicing(String... parts) {
String escaped = IdUtil.escape(ID_SPLITOR, ESCAPE, parts);
return IdGenerator.of(escaped);
}
public static Id splicingWithNoEscape(String... parts) {
String escaped = String.join(ID_SPLITOR_STR, parts);
return IdGenerator.of(escaped);
}
public static Id generateBinaryId(Id id) {
if (id instanceof BinaryId) {
return id;
}
BytesBuffer buffer = BytesBuffer.allocate(1 + id.length());
BinaryId binaryId = new BinaryId(buffer.writeId(id).bytes(), id);
return binaryId;
}
/**
* Parse a single id into multiple parts with ID_SPLITOR
* @param id the id object to be parsed
* @return parsed string id parts
*/
public static String[] parse(Id id) {
return IdUtil.unescape(id.asString(), ID_SPLITOR_STR, ESCAPE_STR);
}
}

View File

@ -0,0 +1,153 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.options;
import org.apache.hugegraph.config.ConfigListOption;
import org.apache.hugegraph.config.ConfigOption;
import org.apache.hugegraph.config.OptionHolder;
import java.security.SecureRandom;
import java.util.Base64;
import static org.apache.hugegraph.config.OptionChecker.*;
public class AuthOptions extends OptionHolder {
private AuthOptions() {
super();
}
private static volatile AuthOptions instance;
public static synchronized AuthOptions instance() {
if (instance == null) {
instance = new AuthOptions();
instance.registerOptions();
}
return instance;
}
public static final ConfigOption<String> AUTH_TOKEN_SECRET =
new ConfigOption<>(
"auth.token_secret",
"Secret key of HS256 algorithm.",
disallowEmpty(),
"FXQXbJtbCLxODc6tGci732pkH1cyf8Qg"
);
public static final ConfigOption<Double> AUTH_AUDIT_LOG_RATE =
new ConfigOption<>(
"auth.audit_log_rate",
"The max rate of audit log output per user, " +
"default value is 1000 records per second.",
rangeDouble(0.0, Double.MAX_VALUE),
1000.0
);
public static final ConfigOption<Long> AUTH_PROXY_CACHE_EXPIRE =
new ConfigOption<>(
"auth.proxy_cache_expire",
"The expiration time in seconds of auth cache in " +
"auth client.",
rangeInt(0L, Long.MAX_VALUE),
(1 * 60L)
);
public static final ConfigOption<Long> AUTH_CACHE_CAPACITY =
new ConfigOption<>(
"auth.cache_capacity",
"The max cache capacity of each auth cache item.",
rangeInt(0L, Long.MAX_VALUE),
(1024 * 10L)
);
public static final ConfigOption<String> AUTHENTICATOR =
new ConfigOption<>(
"auth.authenticator",
"The class path of authenticator implementation. " +
"e.g., org.apache.hugegraph.auth.StandardAuthenticator, " +
"or org.apache.hugegraph.auth.ConfigAuthenticator.",
null,
""
);
public static final ConfigOption<String> AUTH_GRAPH_STORE =
new ConfigOption<>(
"auth.graph_store",
"The name of graph used to store authentication information, " +
"like users, only for org.apache.hugegraph.auth.StandardAuthenticator.",
disallowEmpty(),
"hugegraph"
);
public static final ConfigOption<String> AUTH_ADMIN_TOKEN =
new ConfigOption<>(
"auth.admin_token",
"Token for administrator operations, " +
"only for org.apache.hugegraph.auth.ConfigAuthenticator.",
disallowEmpty(),
"162f7848-0b6d-4faf-b557-3a0797869c55"
);
public static final ConfigListOption<String> AUTH_USER_TOKENS =
new ConfigListOption<>(
"auth.user_tokens",
"The map of user tokens with name and password, " +
"only for org.apache.hugegraph.auth.ConfigAuthenticator.",
disallowEmpty(),
"hugegraph:9fd95c9c-711b-415b-b85f-d4df46ba5c31"
);
public static final ConfigOption<String> AUTH_REMOTE_URL =
new ConfigOption<>(
"auth.remote_url",
"If the address is empty, it provide auth service, " +
"otherwise it is auth client and also provide auth service " +
"through rpc forwarding. The remote url can be set to " +
"multiple addresses, which are concat by ','.",
null,
""
);
public static final ConfigOption<Long> AUTH_CACHE_EXPIRE =
new ConfigOption<>(
"auth.cache_expire",
"The expiration time in seconds of auth cache in " +
"auth client and auth server.",
rangeInt(0L, Long.MAX_VALUE),
(60 * 10L)
);
public static final ConfigOption<Long> AUTH_TOKEN_EXPIRE =
new ConfigOption<>(
"auth.token_expire",
"The expiration time in seconds after token created",
rangeInt(0L, Long.MAX_VALUE),
(3600 * 24L)
);
private static String generateRandomBase64Key() {
SecureRandom random = new SecureRandom();
// 32 bytes for HMAC-SHA256
byte[] bytes = new byte[32];
random.nextBytes(bytes);
return Base64.getEncoder().encodeToString(bytes);
}
}

View File

@ -0,0 +1,666 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hugegraph.options;
import org.apache.hugegraph.config.ConfigConvOption;
import org.apache.hugegraph.config.ConfigOption;
import org.apache.hugegraph.config.OptionHolder;
import org.apache.hugegraph.query.Query;
import org.apache.hugegraph.type.define.CollectionType;
import org.apache.hugegraph.util.Bytes;
import static org.apache.hugegraph.config.OptionChecker.*;
import static org.apache.hugegraph.query.Query.COMMIT_BATCH;
public class CoreOptions extends OptionHolder {
public static final int CPUS = Runtime.getRuntime().availableProcessors();
public static final ConfigOption<String> GREMLIN_GRAPH =
new ConfigOption<>(
"gremlin.graph",
"Gremlin entrance to create graph.",
disallowEmpty(),
"org.apache.hugegraph.HugeFactory"
);
public static final ConfigOption<String> BACKEND =
new ConfigOption<>(
"backend",
"The data store type.",
disallowEmpty(),
"memory"
);
public static final ConfigOption<String> STORE =
new ConfigOption<>(
"store",
"The database name like Cassandra Keyspace.",
disallowEmpty(),
"hugegraph"
);
public static final ConfigOption<String> STORE_GRAPH =
new ConfigOption<>(
"store.graph",
"The graph table name, which store vertex, edge and property.",
disallowEmpty(),
"g"
);
public static final ConfigOption<String> ALIAS_NAME =
new ConfigOption<>(
"alias.graph.id",
"The graph alias id.",
""
);
public static final ConfigOption<String> SERIALIZER =
new ConfigOption<>(
"serializer",
"The serializer for backend store, like: text/binary/cassandra.",
disallowEmpty(),
"text"
);
public static final ConfigOption<Boolean> RAFT_MODE =
new ConfigOption<>(
"raft.mode",
"Whether the backend storage works in raft mode.",
disallowEmpty(),
false
);
public static final ConfigOption<Boolean> RAFT_SAFE_READ =
new ConfigOption<>(
"raft.safe_read",
"Whether to use linearly consistent read.",
disallowEmpty(),
false
);
public static final ConfigOption<String> RAFT_PATH =
new ConfigOption<>(
"raft.path",
"The log path of current raft node.",
disallowEmpty(),
"./raftlog"
);
public static final ConfigOption<Boolean> RAFT_REPLICATOR_PIPELINE =
new ConfigOption<>(
"raft.use_replicator_pipeline",
"Whether to use replicator line, when turned on it " +
"multiple logs can be sent in parallel, and the next log " +
"doesn't have to wait for the ack message of the current " +
"log to be sent.",
disallowEmpty(),
true
);
public static final ConfigOption<Integer> RAFT_ELECTION_TIMEOUT =
new ConfigOption<>(
"raft.election_timeout",
"Timeout in milliseconds to launch a round of election.",
rangeInt(0, Integer.MAX_VALUE),
10000
);
public static final ConfigOption<Integer> RAFT_SNAPSHOT_INTERVAL =
new ConfigOption<>(
"raft.snapshot_interval",
"The interval in seconds to trigger snapshot save.",
rangeInt(0, Integer.MAX_VALUE),
3600
);
public static final ConfigOption<Integer> RAFT_SNAPSHOT_THREADS =
new ConfigOption<>(
"raft.snapshot_threads",
"The thread number used to do snapshot.",
rangeInt(0, Integer.MAX_VALUE),
4
);
public static final ConfigOption<Boolean> RAFT_SNAPSHOT_PARALLEL_COMPRESS =
new ConfigOption<>(
"raft.snapshot_parallel_compress",
"Whether to enable parallel compress.",
disallowEmpty(),
false
);
public static final ConfigOption<Integer> RAFT_SNAPSHOT_COMPRESS_THREADS =
new ConfigOption<>(
"raft.snapshot_compress_threads",
"The thread number used to do snapshot compress.",
rangeInt(0, Integer.MAX_VALUE),
4
);
public static final ConfigOption<Integer> RAFT_SNAPSHOT_DECOMPRESS_THREADS =
new ConfigOption<>(
"raft.snapshot_decompress_threads",
"The thread number used to do snapshot decompress.",
rangeInt(0, Integer.MAX_VALUE),
4
);
public static final ConfigOption<Integer> RAFT_BACKEND_THREADS =
new ConfigOption<>(
"raft.backend_threads",
"The thread number used to apply task to backend.",
rangeInt(0, Integer.MAX_VALUE),
CPUS
);
public static final ConfigOption<Integer> RAFT_READ_INDEX_THREADS =
new ConfigOption<>(
"raft.read_index_threads",
"The thread number used to execute reading index.",
rangeInt(0, Integer.MAX_VALUE),
8
);
public static final ConfigOption<String> RAFT_READ_STRATEGY =
new ConfigOption<>(
"raft.read_strategy",
"The linearizability of read strategy.",
allowValues("ReadOnlyLeaseBased", "ReadOnlySafe"),
"ReadOnlyLeaseBased"
);
public static final ConfigOption<Integer> RAFT_APPLY_BATCH =
new ConfigOption<>(
"raft.apply_batch",
"The apply batch size to trigger disruptor event handler.",
positiveInt(),
// jraft default value is 32
1
);
public static final ConfigOption<Integer> RAFT_QUEUE_SIZE =
new ConfigOption<>(
"raft.queue_size",
"The disruptor buffers size for jraft RaftNode, " +
"StateMachine and LogManager.",
positiveInt(),
// jraft default value is 16384
16384
);
public static final ConfigOption<Integer> RAFT_QUEUE_PUBLISH_TIMEOUT =
new ConfigOption<>(
"raft.queue_publish_timeout",
"The timeout in second when publish event into disruptor.",
positiveInt(),
// jraft default value is 10(sec)
60
);
public static final ConfigOption<Integer> RAFT_RPC_THREADS =
new ConfigOption<>(
"raft.rpc_threads",
"The rpc threads for jraft RPC layer",
positiveInt(),
// jraft default value is 80
Math.max(CPUS * 2, 80)
);
public static final ConfigOption<Integer> RAFT_RPC_CONNECT_TIMEOUT =
new ConfigOption<>(
"raft.rpc_connect_timeout",
"The rpc connect timeout for jraft rpc.",
positiveInt(),
// jraft default value is 1000(ms)
5000
);
public static final ConfigOption<Integer> RAFT_RPC_TIMEOUT =
new ConfigOption<>(
"raft.rpc_timeout",
"The general rpc timeout in seconds for jraft rpc.",
positiveInt(),
// jraft default value is 5s
60
);
public static final ConfigOption<Integer> RAFT_INSTALL_SNAPSHOT_TIMEOUT =
new ConfigOption<>(
"raft.install_snapshot_rpc_timeout",
"The install snapshot rpc timeout in seconds for jraft rpc.",
positiveInt(),
// jraft default value is 5 minutes
10 * 60 * 60
);
public static final ConfigOption<Integer> RAFT_RPC_BUF_LOW_WATER_MARK =
new ConfigOption<>(
"raft.rpc_buf_low_water_mark",
"The ChannelOutboundBuffer's low water mark of netty, " +
"when buffer size less than this size, the method " +
"ChannelOutboundBuffer.isWritable() will return true, " +
"it means that low downstream pressure or good network.",
positiveInt(),
10 * 1024 * 1024
);
public static final ConfigOption<Integer> RAFT_RPC_BUF_HIGH_WATER_MARK =
new ConfigOption<>(
"raft.rpc_buf_high_water_mark",
"The ChannelOutboundBuffer's high water mark of netty, " +
"only when buffer size exceed this size, the method " +
"ChannelOutboundBuffer.isWritable() will return false, " +
"it means that the downstream pressure is too great to " +
"process the request or network is very congestion, " +
"upstream needs to limit rate at this time.",
positiveInt(),
20 * 1024 * 1024
);
public static final ConfigOption<Integer> RATE_LIMIT_WRITE =
new ConfigOption<>(
"rate_limit.write",
"The max rate(items/s) to add/update/delete vertices/edges.",
rangeInt(0, Integer.MAX_VALUE),
0
);
public static final ConfigOption<Integer> RATE_LIMIT_READ =
new ConfigOption<>(
"rate_limit.read",
"The max rate(times/s) to execute query of vertices/edges.",
rangeInt(0, Integer.MAX_VALUE),
0
);
public static final ConfigOption<Long> TASK_SCHEDULE_PERIOD =
new ConfigOption<>(
"task.schedule_period",
"Period time when scheduler to schedule task",
rangeInt(0L, Long.MAX_VALUE),
10L
);
public static final ConfigOption<Long> TASK_WAIT_TIMEOUT =
new ConfigOption<>(
"task.wait_timeout",
"Timeout in seconds for waiting for the task to " +
"complete, such as when truncating or clearing the " +
"backend.",
rangeInt(0L, Long.MAX_VALUE),
10L
);
public static final ConfigOption<Long> TASK_INPUT_SIZE_LIMIT =
new ConfigOption<>(
"task.input_size_limit",
"The job input size limit in bytes.",
rangeInt(0L, Bytes.GB),
16 * Bytes.MB
);
public static final ConfigOption<Long> TASK_RESULT_SIZE_LIMIT =
new ConfigOption<>(
"task.result_size_limit",
"The job result size limit in bytes.",
rangeInt(0L, Bytes.GB),
16 * Bytes.MB
);
public static final ConfigOption<Integer> TASK_TTL_DELETE_BATCH =
new ConfigOption<>(
"task.ttl_delete_batch",
"The batch size used to delete expired data.",
rangeInt(1, 500),
1
);
public static final ConfigOption<String> SCHEDULER_TYPE =
new ConfigOption<>(
"task.scheduler_type",
"The type of scheduler used in distribution system.",
allowValues("local", "distributed"),
"local"
);
public static final ConfigOption<Boolean> TASK_SYNC_DELETION =
new ConfigOption<>(
"task.sync_deletion",
"Whether to delete schema or expired data synchronously.",
disallowEmpty(),
false
);
public static final ConfigOption<Integer> TASK_RETRY =
new ConfigOption<>(
"task.retry",
"Task retry times.",
rangeInt(0, 3),
0
);
public static final ConfigOption<Long> STORE_CONN_DETECT_INTERVAL =
new ConfigOption<>(
"store.connection_detect_interval",
"The interval in seconds for detecting connections, " +
"if the idle time of a connection exceeds this value, " +
"detect it and reconnect if needed before using, " +
"value 0 means detecting every time.",
rangeInt(0L, Long.MAX_VALUE),
600L
);
public static final ConfigOption<String> VERTEX_DEFAULT_LABEL =
new ConfigOption<>(
"vertex.default_label",
"The default vertex label.",
disallowEmpty(),
"vertex"
);
public static final ConfigOption<Boolean> VERTEX_CHECK_CUSTOMIZED_ID_EXIST =
new ConfigOption<>(
"vertex.check_customized_id_exist",
"Whether to check the vertices exist for those using " +
"customized id strategy.",
disallowEmpty(),
false
);
public static final ConfigOption<Boolean> VERTEX_REMOVE_LEFT_INDEX =
new ConfigOption<>(
"vertex.remove_left_index_at_overwrite",
"Whether remove left index at overwrite.",
disallowEmpty(),
false
);
public static final ConfigOption<Boolean> VERTEX_ADJACENT_VERTEX_EXIST =
new ConfigOption<>(
"vertex.check_adjacent_vertex_exist",
"Whether to check the adjacent vertices of edges exist.",
disallowEmpty(),
false
);
public static final ConfigOption<Boolean> VERTEX_ADJACENT_VERTEX_LAZY =
new ConfigOption<>(
"vertex.lazy_load_adjacent_vertex",
"Whether to lazy load adjacent vertices of edges.",
disallowEmpty(),
true
);
public static final ConfigOption<Integer> VERTEX_PART_EDGE_COMMIT_SIZE =
new ConfigOption<>(
"vertex.part_edge_commit_size",
"Whether to enable the mode to commit part of edges of " +
"vertex, enabled if commit size > 0, 0 meas disabled.",
rangeInt(0, (int) Query.DEFAULT_CAPACITY),
5000
);
public static final ConfigOption<Boolean> VERTEX_ENCODE_PK_NUMBER =
new ConfigOption<>(
"vertex.encode_primary_key_number",
"Whether to encode number value of primary key " +
"in vertex id.",
disallowEmpty(),
true
);
public static final ConfigOption<Integer> VERTEX_TX_CAPACITY =
new ConfigOption<>(
"vertex.tx_capacity",
"The max size(items) of vertices(uncommitted) in " +
"transaction.",
rangeInt((int) COMMIT_BATCH, 1000000),
10000
);
public static final ConfigOption<Boolean> QUERY_IGNORE_INVALID_DATA =
new ConfigOption<>(
"query.ignore_invalid_data",
"Whether to ignore invalid data of vertex or edge.",
disallowEmpty(),
true
);
public static final ConfigOption<Boolean> QUERY_OPTIMIZE_AGGR_BY_INDEX =
new ConfigOption<>(
"query.optimize_aggregate_by_index",
"Whether to optimize aggregate query(like count) by index.",
disallowEmpty(),
false
);
public static final ConfigOption<Integer> QUERY_BATCH_SIZE =
new ConfigOption<>(
"query.batch_size",
"The size of each batch when querying by batch.",
rangeInt(1, (int) Query.DEFAULT_CAPACITY),
1000
);
public static final ConfigOption<Integer> QUERY_PAGE_SIZE =
new ConfigOption<>(
"query.page_size",
"The size of each page when querying by paging.",
rangeInt(1, (int) Query.DEFAULT_CAPACITY),
500
);
public static final ConfigOption<Integer> QUERY_INDEX_INTERSECT_THRESHOLD =
new ConfigOption<>(
"query.index_intersect_threshold",
"The maximum number of intermediate results to " +
"intersect indexes when querying by multiple single " +
"index properties.",
rangeInt(1, (int) Query.DEFAULT_CAPACITY),
1000
);
public static final ConfigOption<String> SCHEMA_INIT_TEMPLATE =
new ConfigOption<>(
"schema.init_template",
"The template schema used to init graph",
null,
""
);
public static final ConfigOption<Boolean> SCHEMA_INDEX_REBUILD_USING_PUSHDOWN =
new ConfigOption<>(
"schema.index_rebuild_using_pushdown",
"Whether to use pushdown when to create/rebuid index.",
true
);
public static final ConfigOption<Boolean> QUERY_RAMTABLE_ENABLE =
new ConfigOption<>(
"query.ramtable_enable",
"Whether to enable ramtable for query of adjacent edges.",
disallowEmpty(),
false
);
public static final ConfigOption<Long> QUERY_RAMTABLE_VERTICES_CAPACITY =
new ConfigOption<>(
"query.ramtable_vertices_capacity",
"The maximum number of vertices in ramtable, " +
"generally the largest vertex id is used as capacity.",
rangeInt(1L, Integer.MAX_VALUE * 2L),
10000000L
);
public static final ConfigOption<Integer> QUERY_RAMTABLE_EDGES_CAPACITY =
new ConfigOption<>(
"query.ramtable_edges_capacity",
"The maximum number of edges in ramtable, " +
"include OUT and IN edges.",
rangeInt(1, Integer.MAX_VALUE),
20000000
);
/**
* The schema name rule:
* 1. Not allowed end with spaces
* 2. Not allowed start with '~'
*/
public static final ConfigOption<String> SCHEMA_ILLEGAL_NAME_REGEX =
new ConfigOption<>(
"schema.illegal_name_regex",
"The regex specified the illegal format for schema name.",
disallowEmpty(),
".*\\s+$|~.*"
);
public static final ConfigOption<Long> SCHEMA_CACHE_CAPACITY =
new ConfigOption<>(
"schema.cache_capacity",
"The max cache size(items) of schema cache.",
rangeInt(0L, Long.MAX_VALUE),
10000L
);
public static final ConfigOption<String> VERTEX_CACHE_TYPE =
new ConfigOption<>(
"vertex.cache_type",
"The type of vertex cache, allowed values are [l1, l2].",
allowValues("l1", "l2"),
"l2"
);
public static final ConfigOption<Long> VERTEX_CACHE_CAPACITY =
new ConfigOption<>(
"vertex.cache_capacity",
"The max cache size(items) of vertex cache.",
rangeInt(0L, Long.MAX_VALUE),
(1000 * 1000 * 10L)
);
public static final ConfigOption<Integer> VERTEX_CACHE_EXPIRE =
new ConfigOption<>(
"vertex.cache_expire",
"The expiration time in seconds of vertex cache.",
rangeInt(0, Integer.MAX_VALUE),
(60 * 10)
);
public static final ConfigOption<String> EDGE_CACHE_TYPE =
new ConfigOption<>(
"edge.cache_type",
"The type of edge cache, allowed values are [l1, l2].",
allowValues("l1", "l2"),
"l2"
);
public static final ConfigOption<Long> EDGE_CACHE_CAPACITY =
new ConfigOption<>(
"edge.cache_capacity",
"The max cache size(items) of edge cache.",
rangeInt(0L, Long.MAX_VALUE),
((long) 1000 * 1000)
);
public static final ConfigOption<Integer> EDGE_CACHE_EXPIRE =
new ConfigOption<>(
"edge.cache_expire",
"The expiration time in seconds of edge cache.",
rangeInt(0, Integer.MAX_VALUE),
(60 * 10)
);
public static final ConfigOption<Long> SNOWFLAKE_WORKER_ID =
new ConfigOption<>(
"snowflake.worker_id",
"The worker id of snowflake id generator.",
disallowEmpty(),
0L
);
public static final ConfigOption<Long> SNOWFLAKE_DATACENTER_ID =
new ConfigOption<>(
"snowflake.datacenter_id",
"The datacenter id of snowflake id generator.",
disallowEmpty(),
0L
);
public static final ConfigOption<Boolean> SNOWFLAKE_FORCE_STRING =
new ConfigOption<>(
"snowflake.force_string",
"Whether to force the snowflake long id to be a string.",
disallowEmpty(),
false
);
public static final ConfigOption<String> TEXT_ANALYZER =
new ConfigOption<>(
"search.text_analyzer",
"Choose a text analyzer for searching the " +
"vertex/edge properties, available type are " +
"[ansj, hanlp, smartcn, jieba, jcseg, " +
"mmseg4j, ikanalyzer].",
disallowEmpty(),
"ikanalyzer"
);
public static final ConfigOption<String> TEXT_ANALYZER_MODE =
new ConfigOption<>(
"search.text_analyzer_mode",
"Specify the mode for the text analyzer, " +
"the available mode of analyzer are " +
"ansj: [BaseAnalysis, IndexAnalysis, ToAnalysis, " +
"NlpAnalysis], " +
"hanlp: [standard, nlp, index, nShort, shortest, speed], " +
"smartcn: [], " +
"jieba: [SEARCH, INDEX], " +
"jcseg: [Simple, Complex], " +
"mmseg4j: [Simple, Complex, MaxWord], " +
"ikanalyzer: [smart, max_word]" +
"}.",
disallowEmpty(),
"smart"
);
public static final ConfigOption<String> COMPUTER_CONFIG =
new ConfigOption<>(
"computer.config",
"The config file path of computer job.",
disallowEmpty(),
"./conf/computer.yaml"
);
public static final ConfigOption<String> K8S_OPERATOR_TEMPLATE =
new ConfigOption<>(
"k8s.operator_template",
"the path of operator container template.",
disallowEmpty(),
"./conf/operator-template.yaml"
);
public static final ConfigOption<String> K8S_QUOTA_TEMPLATE =
new ConfigOption<>(
"k8s.quota_template",
"the path of resource quota template.",
disallowEmpty(),
"./conf/resource-quota-template.yaml"
);
public static final ConfigOption<Integer> OLTP_CONCURRENT_THREADS =
new ConfigOption<>(
"oltp.concurrent_threads",
"Thread number to concurrently execute oltp algorithm.",
rangeInt(0, 65535),
10
);
public static final ConfigOption<Integer> OLTP_CONCURRENT_DEPTH =
new ConfigOption<>(
"oltp.concurrent_depth",
"The min depth to enable concurrent oltp algorithm.",
rangeInt(0, 65535),
10
);
public static final ConfigConvOption<String, CollectionType> OLTP_COLLECTION_TYPE =
new ConfigConvOption<>(
"oltp.collection_type",
"The implementation type of collections " +
"used in oltp algorithm.",
allowValues("JCF", "EC", "FU"),
CollectionType::valueOf,
"EC"
);
public static final ConfigOption<String> PD_PEERS = new ConfigOption<>(
"pd.peers",
"The addresses of pd nodes, separated with commas.",
disallowEmpty(),
"127.0.0.1:8686"
);
public static final ConfigOption<String> MEMORY_MODE = new ConfigOption<>(
"memory.mode",
"The memory mode used for query in HugeGraph.",
disallowEmpty(),
"off-heap"
);
public static final ConfigOption<Long> MAX_MEMORY_CAPACITY = new ConfigOption<>(
"memory.max_capacity",
"The maximum memory capacity that can be managed for all queries in HugeGraph.",
nonNegativeInt(),
Bytes.GB
);
public static final ConfigOption<Long> ONE_QUERY_MAX_MEMORY_CAPACITY = new ConfigOption<>(
"memory.one_query_max_capacity",
"The maximum memory capacity that can be managed for a query in HugeGraph.",
nonNegativeInt(),
Bytes.MB * 100
);
public static final ConfigOption<Long> MEMORY_ALIGNMENT = new ConfigOption<>(
"memory.alignment",
"The alignment used for round memory size.",
nonNegativeInt(),
8L
);
public static final ConfigOption<String> GRAPH_SPACE =
new ConfigOption<>(
"graphspace",
"The graph space name.",
null,
"DEFAULT"
);
private static volatile CoreOptions instance;
private CoreOptions() {
super();
}
public static synchronized CoreOptions instance() {
if (instance == null) {
instance = new CoreOptions();
// Should initialize all static members first, then register.
instance.registerOptions();
}
return instance;
}
}

View File

@ -0,0 +1,61 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.query;
import java.util.Iterator;
@Deprecated
public class Aggregate<P> {
private final AggregateFuncDefine<P> func;
private final String column;
public Aggregate(AggregateFuncDefine func, String column) {
this.func = func;
this.column = column;
}
public AggregateFuncDefine func() {
return this.func;
}
public String column() {
return this.column;
}
public boolean countAll() {
return this.func.countAll() && this.column == null;
}
public P reduce(Iterator<P> results) {
return this.func.reduce(results);
}
public P defaultValue() {
return this.func.defaultValue();
}
@Override
public String toString() {
return String.format("%s(%s)", this.func.string(),
this.column == null ? "*" : this.column);
}
}

View File

@ -0,0 +1,37 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.query;
import java.util.Iterator;
/**
* Definition of aggregation method
*
* @param <P>
*/
public interface AggregateFuncDefine<P extends Object> {
String string();
P defaultValue();
P reduce(Iterator<P> results);
boolean countAll();
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,127 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hugegraph.query;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.apache.hugegraph.id.Id;
import org.apache.hugegraph.structure.BaseElement;
import org.apache.hugegraph.type.HugeType;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.InsertionOrderUtil;
import com.google.common.collect.ImmutableList;
public class IdQuery extends Query {
private static final List<Id> EMPTY_IDS = ImmutableList.of();
// The id(s) will be concated with `or`
private List<Id> ids = EMPTY_IDS;
private boolean mustSortByInput = true;
public IdQuery(HugeType resultType) {
super(resultType);
}
public IdQuery(HugeType resultType, Query originQuery) {
super(resultType, originQuery);
}
public IdQuery(HugeType resultType, Set<Id> ids) {
this(resultType);
this.query(ids);
}
public IdQuery(HugeType resultType, Id id) {
this(resultType);
this.query(id);
}
public IdQuery(Query originQuery, Id id) {
this(originQuery.resultType(), originQuery);
this.query(id);
}
public IdQuery(Query originQuery, Set<Id> ids) {
this(originQuery.resultType(), originQuery);
this.query(ids);
}
public boolean mustSortByInput() {
return this.mustSortByInput;
}
public void mustSortByInput(boolean mustSortedByInput) {
this.mustSortByInput = mustSortedByInput;
}
@Override
public int idsSize() {
return this.ids.size();
}
@Override
public Collection<Id> ids() {
return Collections.unmodifiableList(this.ids);
}
public void resetIds() {
this.ids = EMPTY_IDS;
}
public IdQuery query(Id id) {
E.checkArgumentNotNull(id, "Query id can't be null");
if (this.ids == EMPTY_IDS) {
this.ids = InsertionOrderUtil.newList();
}
int last = this.ids.size() - 1;
if (last >= 0 && id.equals(this.ids.get(last))) {
// The same id as the previous one, just ignore it
return this;
}
this.ids.add(id);
this.checkCapacity(this.ids.size());
return this;
}
public IdQuery query(Set<Id> ids) {
for (Id id : ids) {
this.query(id);
}
return this;
}
@Override
public boolean test(BaseElement element) {
return this.ids.contains(element.id());
}
@Override
public IdQuery copy() {
IdQuery query = (IdQuery) super.copy();
query.ids = this.ids == EMPTY_IDS ? EMPTY_IDS :
InsertionOrderUtil.newList(this.ids);
return query;
}
}

View File

@ -0,0 +1,81 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.query;
import java.util.Collections;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.hugegraph.schema.IndexLabel;
import org.apache.hugegraph.schema.SchemaLabel;
public class MatchedIndex {
private final SchemaLabel schemaLabel;
private final Set<IndexLabel> indexLabels;
public MatchedIndex(SchemaLabel schemaLabel,
Set<IndexLabel> indexLabels) {
this.schemaLabel = schemaLabel;
this.indexLabels = indexLabels;
}
public SchemaLabel schemaLabel() {
return this.schemaLabel;
}
public Set<IndexLabel> indexLabels() {
return Collections.unmodifiableSet(this.indexLabels);
}
public boolean containsSearchIndex() {
for (IndexLabel il : this.indexLabels) {
if (il.indexType().isSearch()) {
return true;
}
}
return false;
}
@Override
public int hashCode() {
return indexLabels.hashCode();
}
@Override
public boolean equals(Object other) {
if (!(other instanceof MatchedIndex)) {
return false;
}
Set<IndexLabel> indexLabels = ((MatchedIndex) other).indexLabels;
return Objects.equals(this.indexLabels, indexLabels);
}
@Override
public String toString() {
String strIndexLabels =
indexLabels.stream().map(i -> i.name()).collect(Collectors.joining(","));
return "MatchedIndex{schemaLabel=" + schemaLabel.name() +
", indexLabels=" + strIndexLabels + '}';
}
}

View File

@ -0,0 +1,720 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hugegraph.query;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import com.google.common.base.Joiner;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.hugegraph.exception.BackendException;
import org.apache.hugegraph.exception.LimitExceedException;
import org.apache.hugegraph.id.Id;
import org.apache.hugegraph.structure.BaseElement;
import org.apache.hugegraph.type.HugeType;
import org.apache.hugegraph.type.define.CollectionType;
import org.apache.hugegraph.type.define.HugeKeys;
import org.apache.hugegraph.util.CollectionUtil;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.InsertionOrderUtil;
import org.apache.hugegraph.util.Log;
import org.apache.hugegraph.util.collection.IdSet;
import org.slf4j.Logger;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
public class Query implements Cloneable {
private static final Logger LOG = Log.logger(Query.class);
// TODO: we should better not use Long.Max as the unify limit number
public static final long NO_LIMIT = Long.MAX_VALUE;
public static final long COMMIT_BATCH = 500L;
public static final long QUERY_BATCH = 100L;
public static final long NO_CAPACITY = -1L;
public static final long DEFAULT_CAPACITY = 800000L; // HugeGraph-777
private static final ThreadLocal<Long> CAPACITY_CONTEXT = new ThreadLocal<>();
protected static final Query NONE = new Query(HugeType.UNKNOWN);
private static final Set<Id> EMPTY_OLAP_PKS = ImmutableSet.of();
private HugeType resultType;
private Map<HugeKeys, Order> orders;
private long offset;
private long actualOffset;
private long actualStoreOffset;
private long limit;
private long skipDegree;
private String page;
private long capacity;
private boolean showHidden;
private boolean showDeleting;
private boolean showExpired;
private boolean olap;
private boolean withProperties;
private OrderType orderType;
private Set<Id> olapPks;
private List<Id> selects = InsertionOrderUtil.newList();
@Deprecated
private transient Aggregate aggregate;
private Query originQuery;
private List<Id> groups = InsertionOrderUtil.newList();
private boolean groupByLabel = false;
// V3.7 aggs
private List<ImmutablePair<Id, AggType>> aggs =
InsertionOrderUtil.newList();
public Query() {
}
private static final ThreadLocal<Long> capacityContext = new ThreadLocal<>();
private static int indexStringValueLength = 20;
public Query(HugeType resultType) {
this(resultType, null);
}
public Query(HugeType resultType, Query originQuery) {
this.resultType = resultType;
this.originQuery = originQuery;
this.orders = null;
this.offset = 0L;
this.actualOffset = 0L;
this.actualStoreOffset = 0L;
this.limit = NO_LIMIT;
this.skipDegree = NO_LIMIT;
this.page = null;
this.capacity = defaultCapacity();
this.showHidden = false;
this.showDeleting = false;
this.withProperties = true;
this.orderType = OrderType.ORDER_STRICT;
this.aggregate = null;
this.showExpired = false;
this.olap = false;
this.olapPks = EMPTY_OLAP_PKS;
}
public void copyBasic(Query query) {
E.checkNotNull(query, "query");
this.offset = query.offset();
this.limit = query.limit();
this.skipDegree = query.skipDegree();
this.page = query.page();
this.capacity = query.capacity();
this.showHidden = query.showHidden();
this.showDeleting = query.showDeleting();
this.withProperties = query.withProperties();
this.orderType = query.orderType();
this.aggregate = query.aggregate();
this.showExpired = query.showExpired();
this.olap = query.olap();
if (query.orders != null) {
this.orders(query.orders);
}
}
public HugeType resultType() {
return this.resultType;
}
public void resultType(HugeType resultType) {
this.resultType = resultType;
}
public Query originQuery() {
return this.originQuery;
}
public void setOriginQuery(Query query) {
this.originQuery = query;
}
public Query rootOriginQuery() {
Query root = this;
while (root.originQuery != null) {
root = root.originQuery;
}
return root;
}
protected void originQuery(Query originQuery) {
this.originQuery = originQuery;
}
public Map<HugeKeys, Order> orders() {
return Collections.unmodifiableMap(this.getOrNewOrders());
}
public void orders(Map<HugeKeys, Order> orders) {
this.orders = InsertionOrderUtil.newMap(orders);
}
public void order(HugeKeys key, Order order) {
this.getOrNewOrders().put(key, order);
}
protected Map<HugeKeys, Order> getOrNewOrders() {
if (this.orders != null) {
return this.orders;
}
this.orders = InsertionOrderUtil.newMap();
return this.orders;
}
public long offset() {
return this.offset;
}
public void offset(long offset) {
E.checkArgument(offset >= 0L, "Invalid offset %s", offset);
this.offset = offset;
}
public void copyOffset(Query parent) {
assert this.offset == 0L || this.offset == parent.offset;
assert this.actualOffset == 0L ||
this.actualOffset == parent.actualOffset;
this.offset = parent.offset;
this.actualOffset = parent.actualOffset;
}
public long actualOffset() {
return this.actualOffset;
}
public void resetActualOffset() {
this.actualOffset = 0L;
this.actualStoreOffset = 0L;
}
public long goOffset(long offset) {
E.checkArgument(offset >= 0L, "Invalid offset value: %s", offset);
if (this.originQuery != null) {
this.goParentOffset(offset);
}
return this.goSelfOffset(offset);
}
private void goParentOffset(long offset) {
assert offset >= 0L;
Query parent = this.originQuery;
while (parent != null) {
parent.actualOffset += offset;
parent = parent.originQuery;
}
}
private long goSelfOffset(long offset) {
assert offset >= 0L;
if (this.originQuery != null) {
this.originQuery.goStoreOffsetBySubQuery(offset);
}
this.actualOffset += offset;
return this.actualOffset;
}
private long goStoreOffsetBySubQuery(long offset) {
Query parent = this.originQuery;
while (parent != null) {
parent.actualStoreOffset += offset;
parent = parent.originQuery;
}
this.actualStoreOffset += offset;
return this.actualStoreOffset;
}
public <T> Set<T> skipOffsetIfNeeded(Set<T> elems) {
/*
* Skip index(index query with offset) for performance optimization.
* We assume one result is returned by each index, but if there are
* overridden index it will cause confusing offset and results.
*/
long fromIndex = this.offset() - this.actualOffset();
if (fromIndex < 0L) {
// Skipping offset is overhead, no need to skip
fromIndex = 0L;
} else if (fromIndex > 0L) {
this.goOffset(fromIndex);
}
E.checkArgument(fromIndex <= Integer.MAX_VALUE,
"Offset must be <= 0x7fffffff, but got '%s'",
fromIndex);
if (fromIndex >= elems.size()) {
return ImmutableSet.of();
}
long toIndex = this.total();
if (this.noLimit() || toIndex > elems.size()) {
toIndex = elems.size();
}
if (fromIndex == 0L && toIndex == elems.size()) {
return elems;
}
assert fromIndex < elems.size();
assert toIndex <= elems.size();
return CollectionUtil.subSet(elems, (int) fromIndex, (int) toIndex);
}
public long remaining() {
if (this.limit == NO_LIMIT) {
return NO_LIMIT;
} else {
return this.total() - this.actualOffset();
}
}
public long total() {
if (this.limit == NO_LIMIT) {
return NO_LIMIT;
} else {
return this.offset + this.limit;
}
}
public long limit() {
if (this.capacity != NO_CAPACITY) {
E.checkArgument(this.limit == Query.NO_LIMIT ||
this.limit <= this.capacity,
"Invalid limit %s, must be <= capacity(%s)",
this.limit, this.capacity);
}
return this.limit;
}
public void limit(long limit) {
E.checkArgument(limit >= 0L || limit == NO_LIMIT,
"Invalid limit %s", limit);
this.limit = limit;
}
public boolean noLimit() {
return this.limit() == NO_LIMIT;
}
public boolean noLimitAndOffset() {
return this.limit() == NO_LIMIT && this.offset() == 0L;
}
public boolean reachLimit(long count) {
long limit = this.limit();
if (limit == NO_LIMIT) {
return false;
}
return count >= (limit + this.offset());
}
/**
* Set or update the offset and limit by a range [start, end)
* NOTE: it will use the min range one: max start and min end
*
* @param start the range start, include it
* @param end the range end, exclude it
*/
public long range(long start, long end) {
// Update offset
long offset = this.offset();
start = Math.max(start, offset);
this.offset(start);
// Update limit
if (end != -1L) {
if (!this.noLimit()) {
end = Math.min(end, offset + this.limit());
} else {
assert end < Query.NO_LIMIT;
}
E.checkArgument(end >= start,
"Invalid range: [%s, %s)", start, end);
this.limit(end - start);
} else {
// Keep the origin limit
assert this.limit() <= Query.NO_LIMIT;
}
return this.limit;
}
public String page() {
if (this.page != null) {
E.checkState(this.limit() != 0L,
"Can't set limit=0 when using paging");
E.checkState(this.offset() == 0L,
"Can't set offset when using paging, but got '%s'",
this.offset());
}
return this.page;
}
public String pageWithoutCheck() {
return this.page;
}
public void page(String page) {
this.page = page;
}
public boolean paging() {
return this.page != null;
}
@Deprecated
public void olap(boolean olap) {
this.olap = olap;
}
@Deprecated
public boolean olap() {
return this.olap;
}
public void olapPks(Set<Id> olapPks) {
for (Id olapPk : olapPks) {
this.olapPk(olapPk);
}
}
public void olapPk(Id olapPk) {
if (this.olapPks == EMPTY_OLAP_PKS) {
this.olapPks = new IdSet(CollectionType.EC);
}
this.olapPks.add(olapPk);
}
public Set<Id> olapPks() {
return this.olapPks;
}
public long capacity() {
return this.capacity;
}
public void capacity(long capacity) {
this.capacity = capacity;
}
public boolean bigCapacity() {
return this.capacity == NO_CAPACITY || this.capacity > DEFAULT_CAPACITY;
}
public void checkCapacity(long count) throws LimitExceedException {
// Throw LimitExceedException if reach capacity
if (this.capacity != Query.NO_CAPACITY && count > this.capacity) {
final int MAX_CHARS = 256;
String query = this.toString();
if (query.length() > MAX_CHARS) {
query = query.substring(0, MAX_CHARS) + "...";
}
throw new LimitExceedException(
"Too many records(must <= %s) for the query: %s",
this.capacity, query);
}
}
public Aggregate aggregate() {
return this.aggregate;
}
public Aggregate aggregateNotNull() {
E.checkArgument(this.aggregate != null,
"The aggregate must be set for number query");
return this.aggregate;
}
public void aggregate(AggregateFuncDefine func, String property) {
this.aggregate = new Aggregate(func, property);
}
public void aggregate(Aggregate aggregate) {
this.aggregate = aggregate;
}
public boolean showHidden() {
return this.showHidden;
}
public void showHidden(boolean showHidden) {
this.showHidden = showHidden;
}
public boolean showDeleting() {
return this.showDeleting;
}
public void showDeleting(boolean showDeleting) {
this.showDeleting = showDeleting;
}
public long skipDegree() {
return this.skipDegree;
}
public void skipDegree(long skipDegree) {
this.skipDegree = skipDegree;
}
public boolean withProperties() {
return this.withProperties;
}
public void withProperties(boolean withProperties) {
this.withProperties = withProperties;
}
public OrderType orderType() {
return this.orderType;
}
public void orderType(OrderType orderType) {
this.orderType = orderType;
}
public boolean showExpired() {
return this.showExpired;
}
public void showExpired(boolean showExpired) {
this.showExpired = showExpired;
}
public Collection<Id> ids() {
return ImmutableList.of();
}
public Collection<Condition> conditions() {
return ImmutableList.of();
}
public int idsSize() {
return 0;
}
public int conditionsSize() {
return 0;
}
public boolean empty() {
return this.idsSize() == 0 && this.conditionsSize() == 0;
}
public boolean test(BaseElement element) {
return true;
}
public Query copy() {
try {
return (Query) this.clone();
} catch (CloneNotSupportedException e) {
throw new BackendException(e);
}
}
@Override
public boolean equals(Object object) {
if (!(object instanceof Query)) {
return false;
}
Query other = (Query) object;
return this.resultType.equals(other.resultType) &&
this.orders().equals(other.orders()) &&
this.offset == other.offset &&
this.limit == other.limit &&
Objects.equals(this.page, other.page) &&
this.ids().equals(other.ids()) &&
this.conditions().equals(other.conditions()) &&
this.withProperties == other.withProperties;
}
@Override
public int hashCode() {
int hash = this.orders().hashCode() ^
Long.hashCode(this.offset) ^
Long.hashCode(this.limit) ^
Objects.hashCode(this.page) ^
this.ids().hashCode() ^
this.conditions().hashCode() ^
this.selects().hashCode() ^
Boolean.hashCode(this.withProperties);
if (this.resultType == null) {
return hash;
} else {
return this.resultType.hashCode() ^ hash;
}
}
@Override
public String toString() {
Map<String, Object> pairs = InsertionOrderUtil.newMap();
if (this.page != null) {
pairs.put("page", String.format("'%s'", this.page));
}
if (this.offset != 0) {
pairs.put("offset", this.offset);
}
if (this.limit != NO_LIMIT) {
pairs.put("limit", this.limit);
}
if (!this.orders().isEmpty()) {
pairs.put("order by", this.orders());
}
StringBuilder sb = new StringBuilder(128);
sb.append("`Query ");
if (this.aggregate != null) {
sb.append(this.aggregate);
} else {
sb.append('*');
}
sb.append(" from ").append(this.resultType);
for (Map.Entry<String, Object> entry : pairs.entrySet()) {
sb.append(' ').append(entry.getKey())
.append(' ').append(entry.getValue()).append(',');
}
if (!pairs.isEmpty()) {
// Delete last comma
sb.deleteCharAt(sb.length() - 1);
}
if (!this.empty()) {
sb.append(" where");
}
// Append ids
if (!this.ids().isEmpty()) {
sb.append(" id in ").append(this.ids());
}
// Append conditions
if (!this.conditions().isEmpty()) {
if (!this.ids().isEmpty()) {
sb.append(" and");
}
sb.append(" ").append(this.conditions());
}
if (!this.groups.isEmpty()) {
sb.append(" group by ").append(Joiner.on(",").join(this.groups));
}
sb.append('`');
return sb.toString();
}
public static long defaultCapacity(long capacity) {
Long old = CAPACITY_CONTEXT.get();
CAPACITY_CONTEXT.set(capacity);
return old != null ? old : DEFAULT_CAPACITY;
}
public static long defaultCapacity() {
Long capacity = CAPACITY_CONTEXT.get();
return capacity != null ? capacity : DEFAULT_CAPACITY;
}
public static void checkForceCapacity(long count)
throws LimitExceedException {
if (count > DEFAULT_CAPACITY) {
throw new LimitExceedException(
"Too many records(must <= %s) for one query",
DEFAULT_CAPACITY);
}
}
public boolean isTaskQuery() {
if (this.resultType() == HugeType.TASK ||
this.resultType == HugeType.VARIABLE) {
return true;
}
return false;
}
public static int getIndexStringValueLength() {
return indexStringValueLength;
}
public static void setIndexStringValueLength(int indexStringValueLengthTmp) {
if (indexStringValueLengthTmp <= 1) {
indexStringValueLengthTmp = 20;
}
indexStringValueLength = indexStringValueLengthTmp;
}
public void select(Id id) {
if (!this.selects.contains(id)) {
this.selects.add(id);
} else {
LOG.warn("id already in selects: {}", id);
}
}
public List<Id> selects() {
return this.selects;
}
public void group(Id id) {
if (!this.groups.contains(id)) {
this.groups.add(id);
} else {
LOG.warn("id already in groups: {}", id);
}
}
public enum OrderType {
// Under batch interface, the requirement for return order
ORDER_NONE, // Allow unordered
ORDER_WITHIN_VERTEX, // Edges within a vertex will not be broken, but there is no order between different vertices.
ORDER_STRICT // Ensure the original input point order
}
public enum Order {
ASC,
DESC
}
public enum AggType {
COUNT,
MAX,
MIN,
AVG,
SUM;
}
}

View File

@ -0,0 +1,62 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.query.serializer;
import java.lang.reflect.Type;
import java.util.Map;
import org.apache.hugegraph.exception.BackendException;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
// TODO: optimize by binary protocol
public abstract class AbstractSerializerAdapter<T> implements JsonSerializer<T>,
JsonDeserializer<T> {
//Note: By overriding the method to get the mapping
public abstract Map<String, Type> validType();
@Override
public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws
JsonParseException {
JsonObject object = json.getAsJsonObject();
String type = object.get("cls").getAsString();
JsonElement element = object.get("el");
try {
return context.deserialize(element, validType().get(type));
} catch (Exception e) {
throw new BackendException("Unknown element type: " + type, e);
}
}
@Override
public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject result = new JsonObject();
Class clazz = src.getClass();
result.add("cls", new JsonPrimitive(clazz.getSimpleName().substring(0, 1).toUpperCase()));
result.add("el", context.serialize(src, clazz));
return result;
}
}

View File

@ -0,0 +1,148 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.query.serializer;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.apache.hugegraph.query.Condition;
import org.apache.hugegraph.type.define.Directions;
import com.google.common.collect.ImmutableMap;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.reflect.TypeToken;
public class QueryAdapter extends AbstractSerializerAdapter<Condition> {
static ImmutableMap<String, Type> cls =
ImmutableMap.<String, Type>builder()
// TODO: uncomment later
.put("N", Condition.Not.class)
.put("A", Condition.And.class)
.put("O", Condition.Or.class)
.put("S", Condition.SyspropRelation.class)
.put("U", Condition.UserpropRelation.class)
.build();
static boolean isPrimitive(Class clz) {
try {
return (clz == Date.class) || ((Class) clz.getField("TYPE").get(null)).isPrimitive();
} catch (Exception e) {
return false;
}
}
@Override
public Map<String, Type> validType() {
return cls;
}
@Override
public Condition deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
Condition condition = super.deserialize(json, typeOfT, context);
if (condition instanceof Condition.Relation) {
JsonObject object = json.getAsJsonObject();
if (object.has("el")) {
JsonElement elElement = object.get("el");
JsonElement valueElement = elElement.getAsJsonObject().get("value");
if (valueElement.isJsonObject()) {
String cls = valueElement.getAsJsonObject().get("cls").getAsString();
try {
Class actualClass = Class.forName(cls);
Object obj = context.deserialize(valueElement, actualClass);
((Condition.Relation) condition).value(obj);
} catch (ClassNotFoundException e) {
throw new JsonParseException(e.getMessage());
}
} else if (elElement.getAsJsonObject().has("valuecls")) {
if (valueElement.isJsonArray()) {
String cls = elElement.getAsJsonObject().get("valuecls").getAsString();
try {
Class actualClass = Class.forName(cls);
Type type = TypeToken.getParameterized(ArrayList.class, actualClass)
.getType();
Object value = context.deserialize(valueElement, type);
((Condition.Relation) condition).value(value);
} catch (ClassNotFoundException e) {
throw new JsonParseException(e.getMessage());
}
} else {
String cls = elElement.getAsJsonObject().get("valuecls").getAsString();
try {
Class actualClass = Class.forName(cls);
Object obj = context.deserialize(valueElement, actualClass);
((Condition.Relation) condition).value(obj);
} catch (ClassNotFoundException e) {
throw new JsonParseException(e.getMessage());
}
}
} else if (valueElement.isJsonPrimitive() &&
valueElement.getAsJsonPrimitive().isString()) {
switch ((String) ((Condition.Relation) condition).value()) {
case "OUT":
((Condition.Relation) condition).value(Directions.OUT);
break;
case "IN":
((Condition.Relation) condition).value(Directions.IN);
break;
default:
break;
}
}
}
}
return condition;
}
@Override
public JsonElement serialize(Condition src, Type typeOfSrc, JsonSerializationContext context) {
JsonElement result = super.serialize(src, typeOfSrc, context);
if (src instanceof Condition.Relation) {
JsonObject object = result.getAsJsonObject();
JsonElement valueElement = object.get("el").getAsJsonObject().get("value");
if (valueElement.isJsonObject()) {
valueElement.getAsJsonObject()
.add("cls",
new JsonPrimitive(
((Condition.Relation) src).value().getClass().getName()));
} else if (isPrimitive(((Condition.Relation) src).value().getClass())) {
object.get("el").getAsJsonObject()
.add("valuecls",
new JsonPrimitive(
((Condition.Relation) src).value().getClass().getName()));
} else if (valueElement.isJsonArray()) {
if (((Condition.Relation) src).value() instanceof List) {
String valueCls =
((List) ((Condition.Relation) src).value()).get(0).getClass().getName();
object.get("el").getAsJsonObject().add("valuecls", new JsonPrimitive(valueCls));
}
}
}
return result;
}
}

View File

@ -0,0 +1,46 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.query.serializer;
import java.lang.reflect.Type;
import java.util.Map;
import org.apache.hugegraph.backend.BinaryId;
import org.apache.hugegraph.id.EdgeId;
import org.apache.hugegraph.id.Id;
import org.apache.hugegraph.id.IdGenerator;
import com.google.common.collect.ImmutableMap;
public class QueryIdAdapter extends AbstractSerializerAdapter<Id> {
static ImmutableMap<String, Type> cls =
ImmutableMap.<String, Type>builder()
.put("E", EdgeId.class)
.put("S", IdGenerator.StringId.class)
.put("L", IdGenerator.LongId.class)
.put("U", IdGenerator.UuidId.class)
.put("O", IdGenerator.ObjectId.class)
.put("B", BinaryId.class)
.build();
@Override
public Map<String, Type> validType() {
return cls;
}
}

View File

@ -0,0 +1,449 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hugegraph.schema;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.hugegraph.HugeGraphSupplier;
import org.apache.hugegraph.id.Id;
import org.apache.hugegraph.id.IdGenerator;
import org.apache.hugegraph.schema.builder.SchemaBuilder;
import org.apache.hugegraph.type.HugeType;
import org.apache.hugegraph.type.define.Directions;
import org.apache.hugegraph.type.define.EdgeLabelType;
import org.apache.hugegraph.type.define.Frequency;
import org.apache.hugegraph.type.define.SchemaStatus;
import org.apache.hugegraph.util.E;
import com.google.common.base.Objects;
public class EdgeLabel extends SchemaLabel {
public static final EdgeLabel NONE = new EdgeLabel(null, NONE_ID, UNDEF);
private Set<Pair<Id, Id>> links = new HashSet<>();
private Id sourceLabel = NONE_ID;
private Id targetLabel = NONE_ID;
private Frequency frequency;
private List<Id> sortKeys;
private EdgeLabelType edgeLabelType = EdgeLabelType.NORMAL;
private Id fatherId;
public EdgeLabel(final HugeGraphSupplier graph, Id id, String name) {
super(graph, id, name);
this.frequency = Frequency.DEFAULT;
this.sortKeys = new ArrayList<>();
}
@Override
public HugeType type() {
return HugeType.EDGE_LABEL;
}
public boolean isFather() {
return this.edgeLabelType.parent();
}
public void edgeLabelType(EdgeLabelType type) {
this.edgeLabelType = type;
}
public EdgeLabelType edgeLabelType() {
return this.edgeLabelType;
}
public boolean hasFather() {
return this.edgeLabelType.sub();
}
public boolean general() {
return this.edgeLabelType.general();
}
public Id fatherId() {
return this.fatherId;
}
public void fatherId(Id fatherId) {
this.fatherId = fatherId;
}
public Frequency frequency() {
return this.frequency;
}
public void frequency(Frequency frequency) {
this.frequency = frequency;
}
public boolean directed() {
// TODO: implement (do we need this method?)
return true;
}
public String sourceLabelName() {
E.checkState(this.links.size() == 1,
"Only edge label has single vertex label pair can call " +
"sourceLabelName(), but current edge label got %s",
this.links.size());
return this.graph.vertexLabelOrNone(this.links.iterator().next().getLeft()).name();
}
public List<Id> linksIds() {
List<Id> ids = new ArrayList<>(this.links.size() * 2);
for (Pair<Id, Id> link : this.links) {
ids.add(link.getLeft());
ids.add(link.getRight());
}
return ids;
}
public void linksIds(Id[] ids) {
this.links = new HashSet<>(ids.length / 2);
for (int i = 0; i < ids.length; i += 2) {
this.links.add(Pair.of(ids[i], ids[i + 1]));
}
}
public Id sourceLabel() {
if (links.size() == 1) {
return links.iterator().next().getLeft();
}
return NONE_ID;
}
public void sourceLabel(Id id) {
E.checkArgument(this.links.isEmpty(),
"Not allowed add source label to an edge label which " +
"already has links");
if (this.targetLabel != NONE_ID) {
this.links.add(Pair.of(id, this.targetLabel));
this.targetLabel = NONE_ID;
} else {
this.sourceLabel = id;
}
}
public String targetLabelName() {
E.checkState(this.links.size() == 1,
"Only edge label has single vertex label pair can call " +
"sourceLabelName(), but current edge label got %s",
this.links.size());
return this.graph.vertexLabelOrNone(this.links.iterator().next().getRight()).name();
}
public Id targetLabel() {
if (links.size() == 1) {
return links.iterator().next().getRight();
}
return NONE_ID;
}
public void targetLabel(Id id) {
E.checkArgument(this.links.isEmpty(),
"Not allowed add source label to an edge label which " +
"already has links");
if (this.sourceLabel != NONE_ID) {
this.links.add(Pair.of(this.sourceLabel, id));
this.sourceLabel = NONE_ID;
} else {
this.targetLabel = id;
}
}
public boolean linkWithLabel(Id id) {
for (Pair<Id, Id> link : this.links) {
if (link.getLeft().equals(id) || link.getRight().equals(id)) {
return true;
}
}
return false;
}
public boolean linkWithVertexLabel(Id label, Directions dir) {
return this.links.stream().anyMatch(pair -> {
Id sourceLabel = pair.getLeft();
Id targetLabel = pair.getRight();
if (dir.equals(Directions.IN)) {
return targetLabel.equals(label);
} else if (dir.equals(Directions.OUT)) {
return sourceLabel.equals(label);
} else if (dir.equals(Directions.BOTH)) {
return targetLabel.equals(label) || sourceLabel.equals(label);
}
return false;
});
}
public boolean checkLinkEqual(Id sourceLabel, Id targetLabel) {
return this.links.contains(Pair.of(sourceLabel, targetLabel));
}
public Set<Pair<Id, Id>> links() {
return this.links;
}
public void links(Pair<Id, Id> link) {
if (this.links == null) {
this.links = new HashSet<>();
}
this.links.add(link);
}
public boolean existSortKeys() {
return !this.sortKeys.isEmpty();
}
public List<Id> sortKeys() {
return Collections.unmodifiableList(this.sortKeys);
}
public void sortKey(Id id) {
this.sortKeys.add(id);
}
public void sortKeys(Id... ids) {
this.sortKeys.addAll(Arrays.asList(ids));
}
public boolean hasSameContent(EdgeLabel other) {
return super.hasSameContent(other) &&
this.frequency == other.frequency &&
Objects.equal(this.sourceLabelName(), other.sourceLabelName()) &&
Objects.equal(this.targetLabelName(), other.targetLabelName()) &&
Objects.equal(this.graph.mapPkId2Name(this.sortKeys),
other.graph.mapPkId2Name(other.sortKeys));
}
public static EdgeLabel undefined(HugeGraphSupplier graph, Id id) {
return new EdgeLabel(graph, id, UNDEF);
}
public interface Builder extends SchemaBuilder<EdgeLabel> {
Id rebuildIndex();
Builder asBase();
Builder withBase(String fatherLabel);
Builder link(String sourceLabel, String targetLabel);
@Deprecated
Builder sourceLabel(String label);
@Deprecated
Builder targetLabel(String label);
Builder singleTime();
Builder multiTimes();
Builder sortKeys(String... keys);
Builder properties(String... properties);
Builder nullableKeys(String... keys);
Builder frequency(Frequency frequency);
Builder ttl(long ttl);
Builder ttlStartTime(String ttlStartTime);
Builder enableLabelIndex(boolean enable);
Builder userdata(String key, Object value);
Builder userdata(Map<String, Object> userdata);
}
@Override
public Map<String, Object> asMap() {
Map<String, Object> map = new HashMap<>();
if (this.sourceLabel() != null && this.sourceLabel() != NONE_ID) {
map.put(P.SOURCE_LABEL, this.sourceLabel().asString());
}
if (this.targetLabel() != null && this.targetLabel() != NONE_ID) {
map.put(P.TARGET_LABEL, this.targetLabel().asString());
}
if (this.properties() != null) {
map.put(P.PROPERTIES, this.properties());
}
if (this.nullableKeys() != null) {
map.put(P.NULLABLE_KEYS, this.nullableKeys());
}
if (this.indexLabels() != null) {
map.put(P.INDEX_LABELS, this.indexLabels());
}
if (this.ttlStartTime() != null) {
map.put(P.TT_START_TIME, this.ttlStartTime().asString());
}
if (this.sortKeys() != null) {
map.put(P.SORT_KEYS, this.sortKeys);
}
map.put(P.EDGELABEL_TYPE, this.edgeLabelType);
if (this.fatherId() != null) {
map.put(P.FATHER_ID, this.fatherId().asString());
}
map.put(P.ENABLE_LABEL_INDEX, this.enableLabelIndex());
map.put(P.TTL, String.valueOf(this.ttl()));
map.put(P.LINKS, this.links());
map.put(P.FREQUENCY, this.frequency().toString());
return super.asMap(map);
}
@SuppressWarnings("unchecked")
public static EdgeLabel fromMap(Map<String, Object> map, HugeGraphSupplier graph) {
Id id = IdGenerator.of((int) map.get(EdgeLabel.P.ID));
String name = (String) map.get(EdgeLabel.P.NAME);
EdgeLabel edgeLabel = new EdgeLabel(graph, id, name);
for (Map.Entry<String, Object> entry : map.entrySet()) {
switch (entry.getKey()) {
case P.ID:
case P.NAME:
break;
case P.STATUS:
edgeLabel.status(
SchemaStatus.valueOf(((String) entry.getValue()).toUpperCase()));
break;
case P.USERDATA:
edgeLabel.userdata(new Userdata((Map<String, Object>) entry.getValue()));
break;
case P.PROPERTIES:
Set<Id> ids = ((List<Integer>) entry.getValue()).stream().map(
IdGenerator::of).collect(Collectors.toSet());
edgeLabel.properties(ids);
break;
case P.NULLABLE_KEYS:
ids = ((List<Integer>) entry.getValue()).stream().map(
IdGenerator::of).collect(Collectors.toSet());
edgeLabel.nullableKeys(ids);
break;
case P.INDEX_LABELS:
ids = ((List<Integer>) entry.getValue()).stream().map(
IdGenerator::of).collect(Collectors.toSet());
edgeLabel.addIndexLabels(ids.toArray(new Id[0]));
break;
case P.ENABLE_LABEL_INDEX:
boolean enableLabelIndex = (Boolean) entry.getValue();
edgeLabel.enableLabelIndex(enableLabelIndex);
break;
case P.TTL:
long ttl = Long.parseLong((String) entry.getValue());
edgeLabel.ttl(ttl);
break;
case P.TT_START_TIME:
long ttlStartTime =
Long.parseLong((String) entry.getValue());
edgeLabel.ttlStartTime(IdGenerator.of(ttlStartTime));
break;
case P.LINKS:
// TODO: serialize and deserialize
List<Map> list = (List<Map>) entry.getValue();
for (Map m : list) {
for (Object key : m.keySet()) {
Id sid = IdGenerator.of(Long.parseLong((String) key));
Id tid = IdGenerator.of(Long.parseLong(String.valueOf(m.get(key))));
edgeLabel.links(Pair.of(sid, tid));
}
}
break;
case P.SOURCE_LABEL:
long sourceLabel =
Long.parseLong((String) entry.getValue());
edgeLabel.sourceLabel(IdGenerator.of(sourceLabel));
break;
case P.TARGET_LABEL:
long targetLabel =
Long.parseLong((String) entry.getValue());
edgeLabel.targetLabel(IdGenerator.of(targetLabel));
break;
case P.FATHER_ID:
long fatherId =
Long.parseLong((String) entry.getValue());
edgeLabel.fatherId(IdGenerator.of(fatherId));
break;
case P.EDGELABEL_TYPE:
EdgeLabelType edgeLabelType =
EdgeLabelType.valueOf(
((String) entry.getValue()).toUpperCase());
edgeLabel.edgeLabelType(edgeLabelType);
break;
case P.FREQUENCY:
Frequency frequency =
Frequency.valueOf(((String) entry.getValue()).toUpperCase());
edgeLabel.frequency(frequency);
break;
case P.SORT_KEYS:
ids = ((List<Integer>) entry.getValue()).stream().map(
IdGenerator::of).collect(Collectors.toSet());
edgeLabel.sortKeys(ids.toArray(new Id[0]));
break;
default:
throw new AssertionError(String.format(
"Invalid key '%s' for edge label",
entry.getKey()));
}
}
return edgeLabel;
}
public static final class P {
public static final String ID = "id";
public static final String NAME = "name";
public static final String STATUS = "status";
public static final String USERDATA = "userdata";
public static final String PROPERTIES = "properties";
public static final String NULLABLE_KEYS = "nullableKeys";
public static final String INDEX_LABELS = "indexLabels";
public static final String ENABLE_LABEL_INDEX = "enableLabelIndex";
public static final String TTL = "ttl";
public static final String TT_START_TIME = "ttlStartTime";
public static final String LINKS = "links";
public static final String SOURCE_LABEL = "sourceLabel";
public static final String TARGET_LABEL = "targetLabel";
public static final String EDGELABEL_TYPE = "edgeLabelType";
public static final String FATHER_ID = "fatherId";
public static final String FREQUENCY = "frequency";
public static final String SORT_KEYS = "sortKeys";
}
}

View File

@ -0,0 +1,498 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hugegraph.schema;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.hugegraph.HugeGraphSupplier;
import org.apache.hugegraph.id.Id;
import org.apache.hugegraph.id.IdGenerator;
import org.apache.hugegraph.schema.builder.SchemaBuilder;
import org.apache.hugegraph.type.define.IndexType;
import org.apache.hugegraph.type.define.SchemaStatus;
import org.apache.hugegraph.type.HugeType;
import org.apache.hugegraph.util.GraphUtils;
import org.apache.hugegraph.util.E;
import com.google.common.base.Objects;
public class IndexLabel extends SchemaElement {
private HugeType baseType;
private Id baseValue;
private IndexType indexType;
private List<Id> indexFields;
public IndexLabel(final HugeGraphSupplier graph, Id id, String name) {
super(graph, id, name);
this.baseType = HugeType.SYS_SCHEMA;
this.baseValue = NONE_ID;
this.indexType = IndexType.SECONDARY;
this.indexFields = new ArrayList<>();
}
protected IndexLabel(long id, String name) {
this(null, IdGenerator.of(id), name);
}
@Override
public HugeType type() {
return HugeType.INDEX_LABEL;
}
public HugeType baseType() {
return this.baseType;
}
public void baseType(HugeType baseType) {
this.baseType = baseType;
}
public Id baseValue() {
return this.baseValue;
}
public void baseValue(Id id) {
this.baseValue = id;
}
public IndexType indexType() {
return this.indexType;
}
public void indexType(IndexType indexType) {
this.indexType = indexType;
}
public HugeType queryType() {
switch (this.baseType) {
case VERTEX_LABEL:
return HugeType.VERTEX;
case EDGE_LABEL:
return HugeType.EDGE;
case SYS_SCHEMA:
return HugeType.SYS_SCHEMA;
default:
throw new AssertionError(String.format(
"Query type of index label is either '%s' or '%s', " +
"but '%s' is used",
HugeType.VERTEX_LABEL, HugeType.EDGE_LABEL,
this.baseType));
}
}
public List<Id> indexFields() {
return Collections.unmodifiableList(this.indexFields);
}
public void indexFields(Id... ids) {
this.indexFields.addAll(Arrays.asList(ids));
}
public void indexField(Id id) {
this.indexFields.add(id);
}
public Id indexField() {
E.checkState(this.indexFields.size() == 1,
"There should be only one field in %s index label, " +
"but got: %s", this.indexType.string(), this.indexFields);
return this.indexFields.get(0);
}
public SchemaLabel baseLabel() {
return getBaseLabel(this.graph, this.baseType, this.baseValue);
}
public SchemaLabel baseElement() {
return getElement(this.graph, this.baseType, this.baseValue);
}
public boolean hasSameContent(IndexLabel other) {
return super.hasSameContent(other) &&
this.indexType == other.indexType &&
this.baseType == other.baseType &&
Objects.equal(this.graph.mapPkId2Name(this.indexFields),
other.graph.mapPkId2Name(other.indexFields));
}
public boolean olap() {
return VertexLabel.OLAP_VL.id().equals(this.baseValue);
}
public Object validValue(Object value) {
if (!(value instanceof Number)) {
return value;
}
Number number = (Number) value;
switch (this.indexType()) {
case RANGE_INT:
return number.intValue();
case RANGE_LONG:
return number.longValue();
case RANGE_FLOAT:
return number.floatValue();
case RANGE_DOUBLE:
return number.doubleValue();
default:
return value;
}
}
// Label index
private static final IndexLabel VL_IL = new IndexLabel(VL_IL_ID, "~vli");
private static final IndexLabel EL_IL = new IndexLabel(EL_IL_ID, "~eli");
// Schema name index
private static final IndexLabel PKN_IL = new IndexLabel(PKN_IL_ID, "~pkni");
private static final IndexLabel VLN_IL = new IndexLabel(VLN_IL_ID, "~vlni");
private static final IndexLabel ELN_IL = new IndexLabel(ELN_IL_ID, "~elni");
private static final IndexLabel ILN_IL = new IndexLabel(ILN_IL_ID, "~ilni");
public static IndexLabel label(HugeType type) {
switch (type) {
case TASK:
case SERVER:
case VERTEX:
return VL_IL;
case EDGE:
case EDGE_OUT:
case EDGE_IN:
return EL_IL;
case PROPERTY_KEY:
return PKN_IL;
case VERTEX_LABEL:
return VLN_IL;
case EDGE_LABEL:
return ELN_IL;
case INDEX_LABEL:
return ILN_IL;
default:
throw new AssertionError(String.format(
"No primitive index label for '%s'", type));
}
}
public static IndexLabel label(HugeGraphSupplier graph, Id id) {
// Primitive IndexLabel first
if (id.asLong() < 0 && id.asLong() > -NEXT_PRIMITIVE_SYS_ID) {
switch ((int) id.asLong()) {
case VL_IL_ID:
return VL_IL;
case EL_IL_ID:
return EL_IL;
case PKN_IL_ID:
return PKN_IL;
case VLN_IL_ID:
return VLN_IL;
case ELN_IL_ID:
return ELN_IL;
case ILN_IL_ID:
return ILN_IL;
default:
throw new AssertionError(String.format(
"No primitive index label for '%s'", id));
}
}
return graph.indexLabel(id);
}
public static SchemaLabel getBaseLabel(HugeGraphSupplier graph,
HugeType baseType,
Object baseValue) {
E.checkNotNull(baseType, "base type", "index label");
E.checkNotNull(baseValue, "base value", "index label");
E.checkArgument(baseValue instanceof String || baseValue instanceof Id,
"The base value must be instance of String or Id, " +
"but got %s(%s)", baseValue,
baseValue.getClass().getSimpleName());
SchemaLabel label;
switch (baseType) {
case VERTEX_LABEL:
if (baseValue instanceof String) {
label = graph.vertexLabel((String) baseValue);
} else {
assert baseValue instanceof Id;
label = graph.vertexLabel((Id) baseValue);
}
break;
case EDGE_LABEL:
if (baseValue instanceof String) {
label = graph.edgeLabel((String) baseValue);
} else {
assert baseValue instanceof Id;
label = graph.edgeLabel((Id) baseValue);
}
break;
default:
throw new AssertionError(String.format(
"Unsupported base type '%s' of index label",
baseType));
}
E.checkArgumentNotNull(label, "Can't find the %s with name '%s'",
baseType.readableName(), baseValue);
return label;
}
public static SchemaLabel getElement(HugeGraphSupplier graph,
HugeType baseType, Object baseValue) {
E.checkNotNull(baseType, "base type", "index label");
E.checkNotNull(baseValue, "base value", "index label");
E.checkArgument(baseValue instanceof String || baseValue instanceof Id,
"The base value must be instance of String or Id, " +
"but got %s(%s)", baseValue,
baseValue.getClass().getSimpleName());
SchemaLabel label;
switch (baseType) {
case VERTEX_LABEL:
if (baseValue instanceof String) {
label = graph.vertexLabel((String) baseValue);
} else {
assert baseValue instanceof Id;
label = graph.vertexLabel((Id) baseValue);
}
break;
case EDGE_LABEL:
if (baseValue instanceof String) {
label = graph.edgeLabel((String) baseValue);
} else {
assert baseValue instanceof Id;
label = graph.edgeLabel((Id) baseValue);
}
break;
default:
throw new AssertionError(String.format(
"Unsupported base type '%s' of index label",
baseType));
}
E.checkArgumentNotNull(label, "Can't find the %s with name '%s'",
baseType.readableName(), baseValue);
return label;
}
public String convert2Groovy(boolean attachIdFlag) {
StringBuilder builder = new StringBuilder(SCHEMA_PREFIX);
// Name
if (!attachIdFlag) {
builder.append("indexLabel").append("('")
.append(this.name())
.append("')");
} else {
builder.append("indexLabel").append("(")
.append(longId()).append(", '")
.append(this.name())
.append("')");
}
// On
switch (this.baseType()) {
case VERTEX_LABEL:
VertexLabel vl = this.graph.vertexLabel(this.baseValue);
builder.append(".onV('")
.append(vl.name())
.append("')");
break;
case EDGE_LABEL:
EdgeLabel el = this.graph.edgeLabel(this.baseValue);
builder.append(".onE('")
.append(el.name())
.append("')");
break;
default:
throw new AssertionError(String.format(
"Invalid base type '%s'", this.baseType()));
}
// By
builder.append(".by(");
List<Id> properties = this.indexFields();
int size = properties.size();
for (Id id : properties) {
PropertyKey pk = this.graph.propertyKey(id);
builder.append("'")
.append(pk.name())
.append("'");
if (--size > 0) {
builder.append(",");
}
}
builder.append(")");
// Index type
builder.append(".");
switch (this.indexType()) {
case SECONDARY:
builder.append("secondary()");
break;
case RANGE_INT:
case RANGE_LONG:
case RANGE_FLOAT:
case RANGE_DOUBLE:
builder.append("range()");
break;
case SEARCH:
builder.append("search()");
break;
case SHARD:
builder.append("shard()");
break;
case UNIQUE:
builder.append("unique()");
break;
default:
throw new AssertionError(String.format(
"Invalid index type '%s'", this.indexType()));
}
// User data
Map<String, Object> userdata = this.userdata();
if (userdata.isEmpty()) {
return builder.toString();
}
for (Map.Entry<String, Object> entry : userdata.entrySet()) {
if (GraphUtils.isHidden(entry.getKey())) {
continue;
}
builder.append(".userdata('")
.append(entry.getKey())
.append("',")
.append(entry.getValue())
.append(")");
}
builder.append(".ifNotExist().create();");
return builder.toString();
}
public interface Builder extends SchemaBuilder<IndexLabel> {
TaskWithSchema createWithTask();
Id rebuild();
Builder onV(String baseValue);
Builder onE(String baseValue);
Builder by(String... fields);
Builder secondary();
Builder range();
Builder search();
Builder shard();
Builder unique();
Builder on(HugeType baseType, String baseValue);
Builder indexType(IndexType indexType);
Builder userdata(String key, Object value);
Builder userdata(Map<String, Object> userdata);
Builder rebuild(boolean rebuild);
}
@Override
public Map<String, Object> asMap() {
HashMap<String, Object> map = new HashMap<>();
map.put(P.BASE_TYPE, this.baseType().name());
map.put(P.BASE_VALUE, this.baseValue().asString());
map.put(P.INDEX_TYPE, this.indexType().name());
map.put(P.INDEX_FIELDS, this.indexFields());
return super.asMap(map);
}
@SuppressWarnings("unchecked")
public static IndexLabel fromMap(Map<String, Object> map, HugeGraphSupplier graph) {
Id id = IdGenerator.of((int) map.get(IndexLabel.P.ID));
String name = (String) map.get(IndexLabel.P.NAME);
IndexLabel indexLabel = new IndexLabel(graph, id, name);
for (Map.Entry<String, Object> entry : map.entrySet()) {
switch (entry.getKey()) {
case P.ID:
case P.NAME:
break;
case P.STATUS:
indexLabel.status(
SchemaStatus.valueOf(((String) entry.getValue()).toUpperCase()));
break;
case P.USERDATA:
indexLabel.userdata(new Userdata((Map<String, Object>) entry.getValue()));
break;
case P.BASE_TYPE:
HugeType hugeType =
HugeType.valueOf(((String) entry.getValue()).toUpperCase());
indexLabel.baseType(hugeType);
break;
case P.BASE_VALUE:
long sourceLabel =
Long.parseLong((String) entry.getValue());
indexLabel.baseValue(IdGenerator.of(sourceLabel));
break;
case P.INDEX_TYPE:
IndexType indexType =
IndexType.valueOf(((String) entry.getValue()).toUpperCase());
indexLabel.indexType(indexType);
break;
case P.INDEX_FIELDS:
List<Id> ids = ((List<Integer>) entry.getValue()).stream().map(
IdGenerator::of).collect(Collectors.toList());
indexLabel.indexFields(ids.toArray(new Id[0]));
break;
default:
throw new AssertionError(String.format(
"Invalid key '%s' for index label",
entry.getKey()));
}
}
return indexLabel;
}
public static final class P {
public static final String ID = "id";
public static final String NAME = "name";
public static final String STATUS = "status";
public static final String USERDATA = "userdata";
public static final String BASE_TYPE = "baseType";
public static final String BASE_VALUE = "baseValue";
public static final String INDEX_TYPE = "indexType";
public static final String INDEX_FIELDS = "indexFields";
}
}

View File

@ -0,0 +1,646 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hugegraph.schema;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.hugegraph.HugeGraphSupplier;
import org.apache.hugegraph.exception.HugeException;
import org.apache.hugegraph.exception.NotSupportException;
import org.apache.hugegraph.id.Id;
import org.apache.hugegraph.id.IdGenerator;
import org.apache.hugegraph.schema.builder.SchemaBuilder;
import org.apache.hugegraph.type.HugeType;
import org.apache.hugegraph.type.Propfiable;
import org.apache.hugegraph.type.define.AggregateType;
import org.apache.hugegraph.type.define.Cardinality;
import org.apache.hugegraph.type.define.DataType;
import org.apache.hugegraph.type.define.SchemaStatus;
import org.apache.hugegraph.type.define.WriteType;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.GraphUtils;
import org.apache.hugegraph.util.LongEncoding;
import static org.apache.hugegraph.type.define.WriteType.OLAP_COMMON;
import static org.apache.hugegraph.type.define.WriteType.OLAP_RANGE;
import static org.apache.hugegraph.type.define.WriteType.OLAP_SECONDARY;
public class PropertyKey extends SchemaElement implements Propfiable {
private DataType dataType;
private Cardinality cardinality;
private AggregateType aggregateType;
private WriteType writeType;
public PropertyKey(final HugeGraphSupplier graph, Id id, String name) {
super(graph, id, name);
this.dataType = DataType.TEXT;
this.cardinality = Cardinality.SINGLE;
this.aggregateType = AggregateType.NONE;
this.writeType = WriteType.OLTP;
}
@Override
public HugeType type() {
return HugeType.PROPERTY_KEY;
}
public DataType dataType() {
return this.dataType;
}
public void dataType(DataType dataType) {
this.dataType = dataType;
}
public Cardinality cardinality() {
return this.cardinality;
}
public void cardinality(Cardinality cardinality) {
this.cardinality = cardinality;
}
public AggregateType aggregateType() {
return this.aggregateType;
}
public void aggregateType(AggregateType aggregateType) {
this.aggregateType = aggregateType;
}
public void writeType(WriteType writeType) {
this.writeType = writeType;
}
public WriteType writeType() {
return this.writeType;
}
public boolean oltp() {
return this.writeType.oltp();
}
public boolean olap() {
return this.writeType.olap();
}
@Override
public Set<Id> properties() {
return Collections.emptySet();
}
public PropertyKey properties(Id... properties) {
if (properties.length > 0) {
throw new NotSupportException("PropertyKey.properties(Id)");
}
return this;
}
public void defineDefaultValue(Object value) {
// TODO add a field default_value
this.userdata().put(Userdata.DEFAULT_VALUE, value);
}
public Object defaultValue() {
// TODO add a field default_value
return this.userdata().get(Userdata.DEFAULT_VALUE);
}
public boolean hasSameContent(PropertyKey other) {
return super.hasSameContent(other) &&
this.dataType == other.dataType() &&
this.cardinality == other.cardinality() &&
this.aggregateType == other.aggregateType() &&
this.writeType == other.writeType();
}
public String clazz() {
String dataType = this.dataType().clazz().getSimpleName();
switch (this.cardinality) {
case SINGLE:
return dataType;
// A set of values: Set<DataType>
case SET:
return String.format("Set<%s>", dataType);
// A list of values: List<DataType>
case LIST:
return String.format("List<%s>", dataType);
default:
throw new AssertionError(String.format(
"Unsupported cardinality: '%s'", this.cardinality));
}
}
public Class<?> implementClazz() {
Class<?> cls;
switch (this.cardinality) {
case SINGLE:
cls = this.dataType().clazz();
break;
// A set of values: Set<DataType>
case SET:
cls = LinkedHashSet.class;
break;
// A list of values: List<DataType>
case LIST:
cls = ArrayList.class;
break;
default:
throw new AssertionError(String.format(
"Unsupported cardinality: '%s'", this.cardinality));
}
return cls;
}
@SuppressWarnings("unchecked")
public <T> T newValue() {
switch (this.cardinality) {
case SET:
return (T) new LinkedHashSet<>();
case LIST:
return (T) new ArrayList<>();
default:
// pass
break;
}
try {
return (T) this.implementClazz().newInstance();
} catch (Exception e) {
throw new HugeException("Failed to new instance of %s: %s",
this.implementClazz(), e.toString());
}
}
/**
* Check property value valid
*
* @param value the property value to be checked data type and cardinality
* @param <V> the property value class
* @return true if data type and cardinality satisfy requirements,
* otherwise false
*/
public <V> boolean checkValueType(V value) {
boolean valid;
switch (this.cardinality) {
case SINGLE:
valid = this.checkDataType(value);
break;
case SET:
valid = value instanceof Set;
valid = valid && this.checkDataType((Set<?>) value);
break;
case LIST:
valid = value instanceof List;
valid = valid && this.checkDataType((List<?>) value);
break;
default:
throw new AssertionError(String.format(
"Unsupported cardinality: '%s'", this.cardinality));
}
return valid;
}
/**
* Check type of the value valid
*
* @param value the property value to be checked data type
* @param <V> the property value original data type
* @return true if the value is or can convert to the data type,
* otherwise false
*/
private <V> boolean checkDataType(V value) {
return this.dataType().clazz().isInstance(value);
}
/**
* Check type of all the values(maybe some list properties) valid
*
* @param values the property values to be checked data type
* @param <V> the property value class
* @return true if all the values are or can convert to the data type,
* otherwise false
*/
private <V> boolean checkDataType(Collection<V> values) {
boolean valid = true;
for (Object o : values) {
if (!this.checkDataType(o)) {
valid = false;
break;
}
}
return valid;
}
public <V> Object serialValue(V value, boolean encodeNumber) {
V validValue = this.validValue(value);
E.checkArgument(validValue != null,
"Invalid property value '%s' for key '%s'",
value, this.name());
E.checkArgument(this.cardinality.single(),
"The cardinality can't be '%s' for navigation key '%s'",
this.cardinality, this.name());
if (this.dataType.isNumber() || this.dataType.isDate()) {
if (encodeNumber) {
return LongEncoding.encodeNumber(validValue);
} else {
return validValue.toString();
}
}
return validValue;
}
public <V> V validValueOrThrow(V value) {
V validValue = this.validValue(value);
if (validValue == null) {
E.checkArgument(false,
"Invalid property value '%s' for key '%s', " +
"expect a value of type %s, actual type %s",
value, this.name(), this.clazz(),
value.getClass().getSimpleName());
}
return validValue;
}
public <V> V validValue(V value) {
try {
return this.convValue(value);
} catch (RuntimeException e) {
throw new IllegalArgumentException(String.format(
"Invalid property value '%s' for key '%s': %s",
value, this.name(), e.getMessage()));
}
}
@SuppressWarnings("unchecked")
private <V, T> V convValue(V value) {
if (value == null) {
return null;
}
if (this.checkValueType(value)) {
// Same as expected type, no conversion required
return value;
}
V validValue = null;
Collection<T> validValues;
if (this.cardinality.single()) {
validValue = this.convSingleValue(value);
} else if (value instanceof Collection) {
assert this.cardinality.multiple();
Collection<T> collection = (Collection<T>) value;
if (value instanceof Set) {
validValues = new LinkedHashSet<>(collection.size());
} else {
assert value instanceof List;
validValues = new ArrayList<>(collection.size());
}
for (T element : collection) {
element = this.convSingleValue(element);
if (element == null) {
validValues = null;
break;
}
validValues.add(element);
}
validValue = (V) validValues;
} else {
assert this.cardinality.multiple();
E.checkArgument(false,
"Property value must be %s, but got '%s'(%s)",
this.cardinality, value,
value.getClass().getSimpleName());
}
return validValue;
}
private <V> V convSingleValue(V value) {
if (value == null) {
return null;
}
if (this.dataType().isNumber()) {
@SuppressWarnings("unchecked")
V number = (V) this.dataType().valueToNumber(value);
return number;
} else if (this.dataType().isDate()) {
@SuppressWarnings("unchecked")
V date = (V) this.dataType().valueToDate(value);
return date;
} else if (this.dataType().isUUID()) {
@SuppressWarnings("unchecked")
V uuid = (V) this.dataType().valueToUUID(value);
return uuid;
} else if (this.dataType().isBlob()) {
@SuppressWarnings("unchecked")
V blob = (V) this.dataType().valueToBlob(value);
return blob;
}
if (this.checkDataType(value)) {
return value;
}
return null;
}
public String convert2Groovy(boolean attachIdFlag) {
StringBuilder builder = new StringBuilder(SCHEMA_PREFIX);
// Name
if (!attachIdFlag) {
builder.append("propertyKey").append("('")
.append(this.name())
.append("')");
} else {
builder.append("propertyKey").append("(")
.append(longId()).append(", '")
.append(this.name())
.append("')");
}
// DataType
switch (this.dataType()) {
case INT:
builder.append(".asInt()");
break;
case LONG:
builder.append(".asLong()");
break;
case DOUBLE:
builder.append(".asDouble()");
break;
case BYTE:
builder.append(".asByte()");
break;
case DATE:
builder.append(".asDate()");
break;
case FLOAT:
builder.append(".asFloat()");
break;
case BLOB:
builder.append(".asBlob()");
break;
case TEXT:
builder.append(".asText()");
break;
case UUID:
builder.append(".asUUID()");
break;
case OBJECT:
builder.append(".asObject()");
break;
case BOOLEAN:
builder.append(".asBoolean()");
break;
default:
throw new AssertionError(String.format(
"Invalid data type '%s'", this.dataType()));
}
// Cardinality
switch (this.cardinality()) {
case SINGLE:
// Single is default, prefer not output
break;
case SET:
builder.append(".valueSet()");
break;
case LIST:
builder.append(".valueList()");
break;
default:
throw new AssertionError(String.format(
"Invalid cardinality '%s'", this.cardinality()));
}
// Aggregate type
switch (this.aggregateType()) {
case NONE:
// NONE is default, prefer not output
break;
case MAX:
builder.append(".calcMax()");
break;
case MIN:
builder.append(".calcMin()");
break;
case SUM:
builder.append(".calcSum()");
break;
case LIST:
builder.append(".calcList()");
break;
case SET:
builder.append(".calcSet()");
break;
case OLD:
builder.append(".calcOld()");
break;
default:
throw new AssertionError(String.format(
"Invalid cardinality '%s'", this.aggregateType()));
}
// Write type
switch (this.writeType()) {
case OLTP:
// OLTP is default, prefer not output
break;
case OLAP_COMMON:
builder.append(".writeType('")
.append(OLAP_COMMON)
.append("')");
break;
case OLAP_RANGE:
builder.append(".writeType('")
.append(OLAP_RANGE)
.append("')");
break;
case OLAP_SECONDARY:
builder.append(".writeType('")
.append(OLAP_SECONDARY)
.append("')");
break;
default:
throw new AssertionError(String.format(
"Invalid write type '%s'", this.writeType()));
}
// User data
Map<String, Object> userdata = this.userdata();
if (userdata.isEmpty()) {
return builder.toString();
}
for (Map.Entry<String, Object> entry : userdata.entrySet()) {
if (GraphUtils.isHidden(entry.getKey())) {
continue;
}
builder.append(".userdata('")
.append(entry.getKey())
.append("',")
.append(entry.getValue())
.append(")");
}
builder.append(".ifNotExist().create();");
return builder.toString();
}
public interface Builder extends SchemaBuilder<PropertyKey> {
TaskWithSchema createWithTask();
Builder asText();
Builder asInt();
Builder asDate();
Builder asUUID();
Builder asBoolean();
Builder asByte();
Builder asBlob();
Builder asDouble();
Builder asFloat();
Builder asLong();
Builder valueSingle();
Builder valueList();
Builder valueSet();
Builder calcMax();
Builder calcMin();
Builder calcSum();
Builder calcOld();
Builder calcSet();
Builder calcList();
Builder writeType(WriteType writeType);
Builder cardinality(Cardinality cardinality);
Builder dataType(DataType dataType);
Builder aggregateType(AggregateType aggregateType);
Builder userdata(String key, Object value);
Builder userdata(Map<String, Object> userdata);
}
@Override
public Map<String, Object> asMap() {
Map<String, Object> map = new HashMap<>();
if (this.dataType != null) {
map.put(P.DATA_TYPE, this.dataType.string());
}
if (this.cardinality != null) {
map.put(P.CARDINALITY, this.cardinality.string());
}
if (this.aggregateType != null) {
map.put(P.AGGREGATE_TYPE, this.aggregateType.string());
}
if (this.writeType != null) {
map.put(P.WRITE_TYPE, this.writeType.string());
}
return super.asMap(map);
}
// change from HugeGraphSupplier HugeGraphSupplier by 2023/3/30 GraphPlatform-2062 core split merge 3.7.0
@SuppressWarnings("unchecked")
public static PropertyKey fromMap(Map<String, Object> map, HugeGraphSupplier graph) {
Id id = IdGenerator.of((int) map.get(P.ID));
String name = (String) map.get(P.NAME);
PropertyKey propertyKey = new PropertyKey(graph, id, name);
for (Map.Entry<String, Object> entry : map.entrySet()) {
switch (entry.getKey()) {
case P.ID:
case P.NAME:
break;
case P.STATUS:
propertyKey.status(SchemaStatus.valueOf(((String) entry.getValue()).toUpperCase()));
break;
case P.USERDATA:
propertyKey.userdata((Map<String, Object>) entry.getValue());
break;
case P.AGGREGATE_TYPE:
propertyKey.aggregateType(AggregateType.valueOf(((String) entry.getValue()).toUpperCase()));
break;
case P.WRITE_TYPE:
propertyKey.writeType(WriteType.valueOf(((String) entry.getValue()).toUpperCase()));
break;
case P.DATA_TYPE:
propertyKey.dataType(DataType.valueOf(((String) entry.getValue()).toUpperCase()));
break;
case P.CARDINALITY:
propertyKey.cardinality(Cardinality.valueOf(((String) entry.getValue()).toUpperCase()));
break;
default:
throw new AssertionError(String.format(
"Invalid key '%s' for property key",
entry.getKey()));
}
}
return propertyKey;
}
public static final class P {
public static final String ID = "id";
public static final String NAME = "name";
public static final String STATUS = "status";
public static final String USERDATA = "userdata";
public static final String DATA_TYPE = "data_type";
public static final String CARDINALITY = "cardinality";
public static final String AGGREGATE_TYPE = "aggregate_type";
public static final String WRITE_TYPE = "write_type";
}
}

View File

@ -0,0 +1,259 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hugegraph.schema;
import java.util.Collections;
import java.util.Map;
import org.apache.hugegraph.HugeGraphSupplier;
import org.apache.hugegraph.exception.HugeException;
import org.apache.hugegraph.id.Id;
import org.apache.hugegraph.id.IdGenerator;
import org.apache.hugegraph.type.Namifiable;
import org.apache.hugegraph.type.Typifiable;
import org.apache.hugegraph.type.define.SchemaStatus;
import org.apache.hugegraph.util.E;
import com.google.common.base.Objects;
import org.apache.hugegraph.util.GraphUtils;
public abstract class SchemaElement implements Namifiable, Typifiable,
Cloneable {
public static final int MAX_PRIMITIVE_SYS_ID = 32;
public static final int NEXT_PRIMITIVE_SYS_ID = 8;
// ABS of system schema id must be below MAX_PRIMITIVE_SYS_ID
protected static final int VL_IL_ID = -1;
protected static final int EL_IL_ID = -2;
protected static final int PKN_IL_ID = -3;
protected static final int VLN_IL_ID = -4;
protected static final int ELN_IL_ID = -5;
protected static final int ILN_IL_ID = -6;
protected static final int OLAP_VL_ID = -7;
// OLAP_ID means all of vertex label ids
public static final Id OLAP_ID = IdGenerator.of(-7);
// OLAP means all of vertex label names
public static final String OLAP = "~olap";
public static final Id NONE_ID = IdGenerator.ZERO;
public static final String UNDEF = "~undefined";
protected static final String SCHEMA_PREFIX = "graph.schema().";
protected final HugeGraphSupplier graph;
private final Id id;
private final String name;
private final Userdata userdata;
private SchemaStatus status;
public SchemaElement(final HugeGraphSupplier graph, Id id, String name) {
E.checkArgumentNotNull(id, "SchemaElement id can't be null");
E.checkArgumentNotNull(name, "SchemaElement name can't be null");
this.graph = graph;
this.id = id;
this.name = name;
this.userdata = new Userdata();
this.status = SchemaStatus.CREATED;
}
public HugeGraphSupplier graph() {
return this.graph;
}
public Id id() {
return this.id;
}
public long longId() {
return this.id.asLong();
}
@Override
public String name() {
return this.name;
}
public Map<String, Object> userdata() {
return Collections.unmodifiableMap(this.userdata);
}
public void userdata(String key, Object value) {
E.checkArgumentNotNull(key, "userdata key");
E.checkArgumentNotNull(value, "userdata value");
this.userdata.put(key, value);
}
public void userdata(Userdata userdata) {
this.userdata.putAll(userdata);
}
public void userdata(Map<String, Object> userdata) {
this.userdata.putAll(userdata);
}
public void removeUserdata(String key) {
E.checkArgumentNotNull(key, "The userdata key can't be null");
this.userdata.remove(key);
}
public void removeUserdata(Userdata userdata) {
for (String key : userdata.keySet()) {
this.userdata.remove(key);
}
}
public SchemaStatus status() {
return this.status;
}
public void status(SchemaStatus status) {
this.status = status;
}
public boolean system() {
return this.longId() < 0L;
}
public boolean primitive() {
long id = this.longId();
return -MAX_PRIMITIVE_SYS_ID <= id && id < 0L;
}
public boolean hidden() {
return GraphUtils.isHidden(this.name());
}
public SchemaElement copy() {
try {
return (SchemaElement) super.clone();
} catch (CloneNotSupportedException e) {
throw new HugeException("Failed to clone schema", e);
}
}
public boolean hasSameContent(SchemaElement other) {
return Objects.equal(this.name(), other.name()) &&
Objects.equal(this.userdata(), other.userdata());
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof SchemaElement)) {
return false;
}
SchemaElement other = (SchemaElement) obj;
return this.type() == other.type() && this.id.equals(other.id());
}
@Override
public int hashCode() {
return this.type().hashCode() ^ this.id.hashCode();
}
@Override
public String toString() {
return String.format("%s(id=%s)", this.name, this.id);
}
public static int schemaId(Id id) {
long l = id.asLong();
// Currently we limit the schema id to within 4 bytes
E.checkArgument(Integer.MIN_VALUE <= l && l <= Integer.MAX_VALUE,
"Schema id is out of bound: %s", l);
return (int) l;
}
public static class TaskWithSchema {
private SchemaElement schemaElement;
private Id task;
public TaskWithSchema(SchemaElement schemaElement, Id task) {
E.checkNotNull(schemaElement, "schema element");
this.schemaElement = schemaElement;
this.task = task;
}
public void propertyKey(PropertyKey propertyKey) {
E.checkNotNull(propertyKey, "property key");
this.schemaElement = propertyKey;
}
public void indexLabel(IndexLabel indexLabel) {
E.checkNotNull(indexLabel, "index label");
this.schemaElement = indexLabel;
}
public PropertyKey propertyKey() {
E.checkState(this.schemaElement instanceof PropertyKey,
"Expect property key, but actual schema type is " +
"'%s'", this.schemaElement.getClass());
return (PropertyKey) this.schemaElement;
}
public IndexLabel indexLabel() {
E.checkState(this.schemaElement instanceof IndexLabel,
"Expect index label, but actual schema type is " +
"'%s'", this.schemaElement.getClass());
return (IndexLabel) this.schemaElement;
}
public SchemaElement schemaElement() {
return this.schemaElement;
}
public Id task() {
return this.task;
}
}
public abstract Map<String, Object> asMap();
public Map<String, Object> asMap(Map<String, Object> map) {
E.checkState(this.id != null,
"Property key id can't be null");
E.checkState(this.name != null,
"Property key name can't be null");
E.checkState(this.status != null,
"Property status can't be null");
map.put(P.ID, this.id);
map.put(P.NAME, this.name);
map.put(P.STATUS, this.status.string());
map.put(P.USERDATA, this.userdata);
return map;
}
public static final class P {
public static final String ID = "id";
public static final String NAME = "name";
public static final String STATUS = "status";
public static final String USERDATA = "userdata";
}
}

View File

@ -0,0 +1,204 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hugegraph.schema;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.apache.hugegraph.HugeGraphSupplier;
import org.apache.hugegraph.exception.HugeException;
import org.apache.hugegraph.id.Id;
import org.apache.hugegraph.id.IdGenerator;
import org.apache.hugegraph.type.HugeType;
import org.apache.hugegraph.type.Indexfiable;
import org.apache.hugegraph.type.Propfiable;
import org.apache.hugegraph.util.E;
import com.google.common.base.Objects;
public abstract class SchemaLabel extends SchemaElement
implements Indexfiable, Propfiable {
private final Set<Id> properties;
private final Set<Id> nullableKeys;
private final Set<Id> indexLabels;
private boolean enableLabelIndex;
private long ttl;
private Id ttlStartTime;
public SchemaLabel(final HugeGraphSupplier graph, Id id, String name) {
super(graph, id, name);
this.properties = new HashSet<>();
this.nullableKeys = new HashSet<>();
this.indexLabels = new HashSet<>();
this.enableLabelIndex = true;
this.ttl = 0L;
this.ttlStartTime = SchemaElement.NONE_ID;
}
@Override
public Set<Id> properties() {
return Collections.unmodifiableSet(this.properties);
}
public Set<Id> extendProperties() {
return this.properties();
}
public void properties(Set<Id> properties) {
this.properties.addAll(properties);
}
public SchemaLabel properties(Id... ids) {
this.properties.addAll(Arrays.asList(ids));
return this;
}
public void property(Id id) {
this.properties.add(id);
}
public Set<Id> nullableKeys() {
return Collections.unmodifiableSet(this.nullableKeys);
}
public void nullableKey(Id id) {
this.nullableKeys.add(id);
}
public void nullableKeys(Id... ids) {
this.nullableKeys.addAll(Arrays.asList(ids));
}
public void nullableKeys(Set<Id> nullableKeys) {
this.nullableKeys.addAll(nullableKeys);
}
@Override
public Set<Id> indexLabels() {
return Collections.unmodifiableSet(this.indexLabels);
}
public Set<Id> extendIndexLabels() {
return this.indexLabels();
}
public void indexLabel(Id id) {
this.indexLabels.add(id);
}
public void indexLabels(Id... ids) {
this.indexLabels.addAll(Arrays.asList(ids));
}
public void addIndexLabel(Id id) {
this.indexLabels.add(id);
}
public void addIndexLabels(Id... ids) {
this.indexLabels.addAll(Arrays.asList(ids));
}
public boolean existsIndexLabel() {
return !this.indexLabels().isEmpty();
}
public void removeIndexLabel(Id id) {
this.indexLabels.remove(id);
}
public boolean enableLabelIndex() {
return this.enableLabelIndex;
}
public void enableLabelIndex(boolean enable) {
this.enableLabelIndex = enable;
}
public boolean undefined() {
return this.name() == UNDEF;
}
public void ttl(long ttl) {
assert ttl >= 0L;
this.ttl = ttl;
}
public long ttl() {
assert this.ttl >= 0L;
return this.ttl;
}
public void ttlStartTime(Id id) {
this.ttlStartTime = id;
}
public Id ttlStartTime() {
return this.ttlStartTime;
}
public String ttlStartTimeName() {
return NONE_ID.equals(this.ttlStartTime) ? null :
this.graph.propertyKey(this.ttlStartTime).name();
}
public boolean hasSameContent(SchemaLabel other) {
return super.hasSameContent(other) && this.ttl == other.ttl &&
this.enableLabelIndex == other.enableLabelIndex &&
Objects.equal(this.graph.mapPkId2Name(this.properties),
other.graph.mapPkId2Name(other.properties)) &&
Objects.equal(this.graph.mapPkId2Name(this.nullableKeys),
other.graph.mapPkId2Name(other.nullableKeys)) &&
Objects.equal(this.graph.mapIlId2Name(this.indexLabels),
other.graph.mapIlId2Name(other.indexLabels)) &&
Objects.equal(this.ttlStartTimeName(), other.ttlStartTimeName());
}
public static Id getLabelId(HugeGraphSupplier graph, HugeType type, Object label) {
E.checkNotNull(graph, "graph");
E.checkNotNull(type, "type");
E.checkNotNull(label, "label");
if (label instanceof Number) {
return IdGenerator.of(((Number) label).longValue());
} else if (label instanceof String) {
if (type.isVertex()) {
return graph.vertexLabel((String) label).id();
} else if (type.isEdge()) {
return graph.edgeLabel((String) label).id();
} else {
throw new HugeException(
"Not support query from '%s' with label '%s'",
type, label);
}
} else {
throw new HugeException(
"The label type must be number or string, but got '%s'",
label.getClass());
}
}
public static Id getVertexLabelId(HugeGraphSupplier graph, Object label) {
return SchemaLabel.getLabelId(graph, HugeType.VERTEX, label);
}
public static Id getEdgeLabelId(HugeGraphSupplier graph, Object label) {
return SchemaLabel.getLabelId(graph, HugeType.EDGE, label);
}
}

View File

@ -0,0 +1,64 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hugegraph.schema;
import java.util.HashMap;
import java.util.Map;
import org.apache.hugegraph.exception.NotAllowException;
import org.apache.hugegraph.type.define.Action;
public class Userdata extends HashMap<String, Object> {
private static final long serialVersionUID = -1235451175617197049L;
public static final String CREATE_TIME = "~create_time";
public static final String DEFAULT_VALUE = "~default_value";
public Userdata() {
}
public Userdata(Map<String, Object> map) {
this.putAll(map);
}
public static void check(Userdata userdata, Action action) {
if (userdata == null) {
return;
}
switch (action) {
case INSERT:
case APPEND:
for (Map.Entry<String, Object> e : userdata.entrySet()) {
if (e.getValue() == null) {
throw new NotAllowException(
"Not allowed to pass null userdata value " +
"when create or append schema");
}
}
break;
case ELIMINATE:
case DELETE:
// pass
break;
default:
throw new AssertionError(String.format(
"Unknown schema action '%s'", action));
}
}
}

View File

@ -0,0 +1,414 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hugegraph.schema;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.hugegraph.HugeGraphSupplier;
import org.apache.hugegraph.id.Id;
import org.apache.hugegraph.id.IdGenerator;
import org.apache.hugegraph.schema.builder.SchemaBuilder;
import org.apache.hugegraph.type.HugeType;
import org.apache.hugegraph.type.define.IdStrategy;
import org.apache.hugegraph.type.define.SchemaStatus;
import org.apache.hugegraph.util.GraphUtils;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableSet;
public class VertexLabel extends SchemaLabel {
public static final VertexLabel NONE = new VertexLabel(null, NONE_ID, UNDEF);
public static final VertexLabel GENERAL =
new VertexLabel(null, NONE_ID, VertexLabel.GENERAL_VL);
// OLAP_VL_ID means all of vertex label ids
private static final Id OLAP_VL_ID = IdGenerator.of(SchemaLabel.OLAP_VL_ID);
// OLAP_VL_NAME means all of vertex label names
private static final String OLAP_VL_NAME = "*olap";
// OLAP_VL means all of vertex labels
public static final VertexLabel OLAP_VL = new VertexLabel(null, OLAP_VL_ID,
OLAP_VL_NAME);
public static final String GENERAL_VL = "~general_vl";
private IdStrategy idStrategy;
private List<Id> primaryKeys;
public VertexLabel(final HugeGraphSupplier graph, Id id, String name) {
super(graph, id, name);
this.idStrategy = IdStrategy.DEFAULT;
this.primaryKeys = new ArrayList<>();
}
@Override
public HugeType type() {
return HugeType.VERTEX_LABEL;
}
public boolean olap() {
return VertexLabel.OLAP_VL.id().equals(this.id());
}
public IdStrategy idStrategy() {
return this.idStrategy;
}
public void idStrategy(IdStrategy idStrategy) {
this.idStrategy = idStrategy;
}
public List<Id> primaryKeys() {
return Collections.unmodifiableList(this.primaryKeys);
}
public void primaryKey(Id id) {
this.primaryKeys.add(id);
}
public void primaryKeys(Id... ids) {
this.primaryKeys.addAll(Arrays.asList(ids));
}
@Override
public Set<Id> extendProperties() {
Set<Id> properties = new HashSet<>();
properties.addAll(this.properties());
properties.addAll(this.primaryKeys);
this.graph().propertyKeys().stream().forEach(pk -> {
if (pk.olap()) {
properties.add(pk.id());
}
});
return Collections.unmodifiableSet(properties);
}
@Override
public Set<Id> extendIndexLabels() {
Set<Id> indexes = new HashSet<>();
indexes.addAll(this.indexLabels());
for (IndexLabel il : this.graph.indexLabels()) {
if (il.olap()) {
indexes.add(il.id());
}
}
return ImmutableSet.copyOf(indexes);
}
public boolean existsLinkLabel() {
return this.graph().existsLinkLabel(this.id());
}
public boolean hasSameContent(VertexLabel other) {
return super.hasSameContent(other) &&
this.idStrategy == other.idStrategy &&
Objects.equal(this.graph.mapPkId2Name(this.primaryKeys),
other.graph.mapPkId2Name(other.primaryKeys));
}
public static VertexLabel undefined(HugeGraphSupplier graph) {
return new VertexLabel(graph, NONE_ID, UNDEF);
}
public static VertexLabel undefined(HugeGraphSupplier graph, Id id) {
return new VertexLabel(graph, id, UNDEF);
}
public String convert2Groovy(boolean attachIdFlag) {
StringBuilder builder = new StringBuilder(SCHEMA_PREFIX);
// Name
if (!attachIdFlag) {
builder.append("vertexLabel").append("('")
.append(this.name())
.append("')");
} else {
builder.append("vertexLabel").append("(")
.append(longId()).append(", '")
.append(this.name())
.append("')");
}
// Properties
Set<Id> properties = this.properties();
if (!properties.isEmpty()) {
builder.append(".").append("properties(");
int size = properties.size();
for (Id id : this.properties()) {
PropertyKey pk = this.graph.propertyKey(id);
builder.append("'")
.append(pk.name())
.append("'");
if (--size > 0) {
builder.append(",");
}
}
builder.append(")");
}
// Id strategy
switch (this.idStrategy()) {
case PRIMARY_KEY:
builder.append(".primaryKeys(");
List<Id> pks = this.primaryKeys();
int size = pks.size();
for (Id id : pks) {
PropertyKey pk = this.graph.propertyKey(id);
builder.append("'")
.append(pk.name())
.append("'");
if (--size > 0) {
builder.append(",");
}
}
builder.append(")");
break;
case CUSTOMIZE_STRING:
builder.append(".useCustomizeStringId()");
break;
case CUSTOMIZE_NUMBER:
builder.append(".useCustomizeNumberId()");
break;
case CUSTOMIZE_UUID:
builder.append(".useCustomizeUuidId()");
break;
case AUTOMATIC:
builder.append(".useAutomaticId()");
break;
default:
throw new AssertionError(String.format(
"Invalid id strategy '%s'", this.idStrategy()));
}
// Nullable keys
properties = this.nullableKeys();
if (!properties.isEmpty()) {
builder.append(".").append("nullableKeys(");
int size = properties.size();
for (Id id : properties) {
PropertyKey pk = this.graph.propertyKey(id);
builder.append("'")
.append(pk.name())
.append("'");
if (--size > 0) {
builder.append(",");
}
}
builder.append(")");
}
// TTL
if (this.ttl() != 0) {
builder.append(".ttl(")
.append(this.ttl())
.append(")");
if (this.ttlStartTime() != null &&
!this.ttlStartTime().equals(SchemaLabel.NONE_ID)) {
PropertyKey pk = this.graph.propertyKey(this.ttlStartTime());
builder.append(".ttlStartTime('")
.append(pk.name())
.append("')");
}
}
// Enable label index
if (this.enableLabelIndex()) {
builder.append(".enableLabelIndex(true)");
} else {
builder.append(".enableLabelIndex(false)");
}
// User data
Map<String, Object> userdata = this.userdata();
if (userdata.isEmpty()) {
return builder.toString();
}
for (Map.Entry<String, Object> entry : userdata.entrySet()) {
if (GraphUtils.isHidden(entry.getKey())) {
continue;
}
builder.append(".userdata('")
.append(entry.getKey())
.append("',")
.append(entry.getValue())
.append(")");
}
builder.append(".ifNotExist().create();");
return builder.toString();
}
public interface Builder extends SchemaBuilder<VertexLabel> {
Id rebuildIndex();
Builder idStrategy(IdStrategy idStrategy);
Builder useAutomaticId();
Builder usePrimaryKeyId();
Builder useCustomizeStringId();
Builder useCustomizeNumberId();
Builder useCustomizeUuidId();
Builder properties(String... properties);
Builder primaryKeys(String... keys);
Builder nullableKeys(String... keys);
Builder ttl(long ttl);
Builder ttlStartTime(String ttlStartTime);
Builder enableLabelIndex(boolean enable);
Builder userdata(String key, Object value);
Builder userdata(Map<String, Object> userdata);
}
@Override
public Map<String, Object> asMap() {
HashMap<String, Object> map = new HashMap();
map.put(P.PROPERTIES, this.properties());
map.put(P.NULLABLE_KEYS, this.nullableKeys());
map.put(P.INDEX_LABELS, this.indexLabels());
map.put(P.ENABLE_LABEL_INDEX, this.enableLabelIndex());
map.put(P.TTL, String.valueOf(this.ttl()));
map.put(P.TT_START_TIME, this.ttlStartTime().asString());
map.put(P.ID_STRATEGY, this.idStrategy().string());
map.put(P.PRIMARY_KEYS, this.primaryKeys());
return super.asMap(map);
}
public boolean generalVl(){
return this.name() == GENERAL_VL;
}
@SuppressWarnings("unchecked")
public static VertexLabel fromMap(Map<String, Object> map, HugeGraphSupplier graph) {
Id id = IdGenerator.of((int) map.get(VertexLabel.P.ID));
String name = (String) map.get(VertexLabel.P.NAME);
VertexLabel vertexLabel = new VertexLabel(graph, id, name);
for (Map.Entry<String, Object> entry : map.entrySet()) {
switch (entry.getKey()) {
case P.ID:
case P.NAME:
break;
case P.STATUS:
vertexLabel.status(
SchemaStatus.valueOf(((String) entry.getValue()).toUpperCase()));
break;
case P.USERDATA:
vertexLabel.userdata(new Userdata((Map<String, Object>) entry.getValue()));
break;
case P.PROPERTIES:
Set<Id> ids = ((List<Integer>) entry.getValue()).stream().map(
IdGenerator::of).collect(Collectors.toSet());
vertexLabel.properties(ids);
break;
case P.NULLABLE_KEYS:
ids = ((List<Integer>) entry.getValue()).stream().map(
IdGenerator::of).collect(Collectors.toSet());
vertexLabel.nullableKeys(ids);
break;
case P.INDEX_LABELS:
ids = ((List<Integer>) entry.getValue()).stream().map(
IdGenerator::of).collect(Collectors.toSet());
vertexLabel.addIndexLabels(ids.toArray(new Id[0]));
break;
case P.ENABLE_LABEL_INDEX:
boolean enableLabelIndex = (Boolean) entry.getValue();
vertexLabel.enableLabelIndex(enableLabelIndex);
break;
case P.TTL:
long ttl = Long.parseLong((String) entry.getValue());
vertexLabel.ttl(ttl);
break;
case P.TT_START_TIME:
long ttlStartTime =
Long.parseLong((String) entry.getValue());
vertexLabel.ttlStartTime(IdGenerator.of(ttlStartTime));
break;
case P.ID_STRATEGY:
IdStrategy idStrategy =
IdStrategy.valueOf(((String) entry.getValue()).toUpperCase());
vertexLabel.idStrategy(idStrategy);
break;
case P.PRIMARY_KEYS:
ids = ((List<Integer>) entry.getValue()).stream().map(
IdGenerator::of).collect(Collectors.toSet());
vertexLabel.primaryKeys(ids.toArray(new Id[0]));
break;
default:
throw new AssertionError(String.format(
"Invalid key '%s' for vertex label",
entry.getKey()));
}
}
return vertexLabel;
}
public static final class P {
public static final String ID = "id";
public static final String NAME = "name";
public static final String STATUS = "status";
public static final String USERDATA = "userdata";
public static final String PROPERTIES = "properties";
public static final String NULLABLE_KEYS = "nullableKeys";
public static final String INDEX_LABELS = "indexLabels";
public static final String ENABLE_LABEL_INDEX = "enableLabelIndex";
public static final String TTL = "ttl";
public static final String TT_START_TIME = "ttlStartTime";
public static final String ID_STRATEGY = "idStrategy";
public static final String PRIMARY_KEYS = "primaryKeys";
}
}

View File

@ -0,0 +1,42 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.schema.builder;
import org.apache.hugegraph.id.Id;
import org.apache.hugegraph.schema.SchemaElement;
public interface SchemaBuilder<T extends SchemaElement> {
public SchemaBuilder<T> id(long id);
public T build();
public T create();
public T append();
public T eliminate();
public Id remove();
public SchemaBuilder<T> ifNotExist();
public SchemaBuilder<T> checkExist(boolean checkExist);
}

View File

@ -0,0 +1,528 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.serializer;
import com.google.common.primitives.Longs;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.NotImplementedException;
import org.apache.hugegraph.HugeGraphSupplier;
import org.apache.hugegraph.backend.BackendColumn;
import org.apache.hugegraph.backend.BinaryId;
import org.apache.hugegraph.exception.HugeException;
import org.apache.hugegraph.id.EdgeId;
import org.apache.hugegraph.id.Id;
import org.apache.hugegraph.id.IdGenerator;
import org.apache.hugegraph.schema.EdgeLabel;
import org.apache.hugegraph.schema.PropertyKey;
import org.apache.hugegraph.schema.SchemaElement;
import org.apache.hugegraph.schema.VertexLabel;
import org.apache.hugegraph.structure.*;
import org.apache.hugegraph.type.HugeType;
import org.apache.hugegraph.type.define.Cardinality;
import org.apache.hugegraph.type.define.EdgeLabelType;
import org.apache.hugegraph.util.Bytes;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.Log;
import org.apache.hugegraph.util.StringEncoding;
import org.slf4j.Logger;
import java.util.Arrays;
import java.util.Base64;
import java.util.Collection;
import java.util.Map;
import static org.apache.hugegraph.schema.SchemaElement.UNDEF;
public class BinaryElementSerializer {
static final BinaryElementSerializer INSTANCE =
new BinaryElementSerializer();
static Logger log = Log.logger(BinaryElementSerializer.class);
public static BinaryElementSerializer getInstance() {
return INSTANCE;
}
/**
* Calculate owner ID of vertex/edge
*
* @param element
* @return
*/
public static Id ownerId(BaseElement element) {
if (element instanceof BaseVertex) {
return element.id();
} else if (element instanceof BaseEdge) {
return ((EdgeId) element.id()).ownerVertexId();
} else {
throw new IllegalArgumentException("Only support get ownerid" +
" of BaseVertex or BaseEdge");
}
}
/**
* Calculate owner ID of index
*
* @param index
* @return
*/
public static Id ownerId(Index index) {
Id elementId = index.elementId();
Id ownerId = null;
if (elementId instanceof EdgeId) {
// Edge ID
ownerId = ((EdgeId) elementId).ownerVertexId();
} else {
// OLAP index
// Normal vertex index
// Normal secondary index
// Vertex/Edge LabelIndex
ownerId = elementId;
}
return ownerId;
}
protected void parseProperty(HugeGraphSupplier graph, Id pkeyId,
BytesBuffer buffer,
BaseElement owner) {
PropertyKey pkey = graph != null ?
graph.propertyKey(pkeyId) :
new PropertyKey(graph, pkeyId, "");
// Parse value
Object value = buffer.readProperty(pkey);
// Set properties of vertex/edge
if (pkey.cardinality() == Cardinality.SINGLE) {
owner.addProperty(pkey, value);
} else {
if (!(value instanceof Collection)) {
throw new HugeException(
"Invalid value of non-single property: %s", value);
}
owner.addProperty(pkey, value);
}
}
public void parseProperties(HugeGraphSupplier graph, BytesBuffer buffer,
BaseElement owner) {
int size = buffer.readVInt();
assert size >= 0;
for (int i = 0; i < size; i++) {
Id pkeyId = IdGenerator.of(buffer.readVInt());
this.parseProperty(graph, pkeyId, buffer, owner);
}
}
/**
* Deserialize vertex KV data into BaseVertex type vertex
*
* @param vertexCol Must be vertex data column
* @param vertex When vertex==null, used for operator sinking, deserialize col data into BaseVertex;
* When vertex!=null, add col information to vertex
*/
public BaseVertex parseVertex(HugeGraphSupplier graph, BackendColumn vertexCol,
BaseVertex vertex) {
if (vertex == null) {
BinaryId binaryId =
BytesBuffer.wrap(vertexCol.name).parseId(HugeType.VERTEX);
vertex = new BaseVertex(binaryId.origin(), VertexLabel.NONE);
}
if (ArrayUtils.isEmpty(vertexCol.value)) {
// No need to parse vertex properties
return vertex;
}
BytesBuffer buffer = BytesBuffer.wrap(vertexCol.value);
Id labelId = buffer.readId();
// Parse vertex label
if (graph != null) {
VertexLabel label = graph.vertexLabelOrNone(labelId);
vertex.correctVertexLabel(label);
} else {
VertexLabel label = new VertexLabel(null, labelId, UNDEF);
vertex.correctVertexLabel(label);
}
// Parse properties
this.parseProperties(graph, buffer, vertex);
// Parse vertex expired time if needed
if (buffer.remaining() > 0 /*edge.hasTtl()*/) {
this.parseExpiredTime(buffer, vertex);
}
return vertex;
}
/**
* Reverse sequence the vertex kv data into vertices of type BaseVertex
*
* @param olapVertexCol It must be a column of vertex data
* @param vertex When vertex==null, it is used for operator sinking to reverse sequence the col data into olapBaseVertex.
* vertex! When =null, add the col information to olapBaseVertex
*/
public BaseVertex parseVertexOlap(HugeGraphSupplier graph,
BackendColumn olapVertexCol, BaseVertex vertex) {
if (vertex == null) {
BytesBuffer idBuffer = BytesBuffer.wrap(olapVertexCol.name);
// read olap property id
idBuffer.readId();
// read vertex id which olap property belongs to
Id vertexId = idBuffer.readId();
vertex = new BaseVertex(vertexId, VertexLabel.NONE);
}
BytesBuffer buffer = BytesBuffer.wrap(olapVertexCol.value);
Id pkeyId = IdGenerator.of(buffer.readVInt());
this.parseProperty(graph, pkeyId, buffer, vertex);
return vertex;
}
/**
* @param cols Deserializing a complete vertex may require multiple cols
* The first col represents the common vertex information in the g+v table, and each subsequent col represents the olap vertices stored in the olap table
*/
public BaseVertex parseVertexFromCols(HugeGraphSupplier graph,
BackendColumn... cols) {
assert cols.length > 0;
BaseVertex vertex = null;
for (int index = 0; index < cols.length; index++) {
BackendColumn col = cols[index];
if (index == 0) {
vertex = this.parseVertex(graph, col, vertex);
} else {
this.parseVertexOlap(graph, col, vertex);
}
}
return vertex;
}
public BaseEdge parseEdge(HugeGraphSupplier graph, BackendColumn edgeCol,
BaseVertex ownerVertex,
boolean withEdgeProperties) {
// owner-vertex + dir + edge-label.id() + subLabel.id() +
// + sort-values + other-vertex
BytesBuffer buffer = BytesBuffer.wrap(edgeCol.name);
// Consume owner-vertex id
Id id = buffer.readId();
if (ownerVertex == null) {
ownerVertex = new BaseVertex(id, VertexLabel.NONE);
}
E.checkState(buffer.remaining() > 0, "Missing column type");
byte type = buffer.read();
if (type == HugeType.EDGE_IN.code() ||
type == HugeType.EDGE_OUT.code()) {
E.checkState(true,
"Invalid column(%s) with unknown type(%s): 0x%s",
id, type & 0xff, Bytes.toHex(edgeCol.name));
}
Id labelId = buffer.readId();
Id subLabelId = buffer.readId();
String sortValues = buffer.readStringWithEnding();
Id otherVertexId = buffer.readId();
boolean direction = EdgeId.isOutDirectionFromCode(type);
BaseEdge edge;
EdgeLabel edgeLabel;
if (graph == null) { /* when calculation sinking */
edgeLabel = new EdgeLabel(null, subLabelId, UNDEF);
// If not equal here, need to add fatherId for correct operator sinking
if (subLabelId != labelId) {
edgeLabel.edgeLabelType(EdgeLabelType.SUB);
edgeLabel.fatherId(labelId);
}
} else {
edgeLabel = graph.edgeLabelOrNone(subLabelId);
}
edge = BaseEdge.constructEdge(graph, ownerVertex, direction,
edgeLabel, sortValues, otherVertexId);
if (!withEdgeProperties /*&& !edge.hasTtl()*/) {
// only skip properties for edge without ttl
// todo: save expiredTime before properties
return edge;
}
if (ArrayUtils.isEmpty(edgeCol.value)) {
// There is no edge-properties here.
return edge;
}
// Parse edge-id + edge-properties
buffer = BytesBuffer.wrap(edgeCol.value);
// Parse edge properties
this.parseProperties(graph, buffer, edge);
/* Skip TTL parsing process first
* Can't determine if edge has TTL through edge, need to judge by bytebuffer length */
// // Parse edge expired time if needed
if (buffer.remaining() > 0 /*edge.hasTtl()*/) {
this.parseExpiredTime(buffer, edge);
}
return edge;
}
/**
* @param graph When parsing index, graph cannot be null
* @param index When null, used for operator sinking, store can restore index based on one col data
*/
public Index parseIndex(HugeGraphSupplier graph, BackendColumn indexCol,
Index index) {
HugeType indexType = parseIndexType(indexCol);
BytesBuffer buffer = BytesBuffer.wrap(indexCol.name);
BinaryId indexId = buffer.readIndexId(indexType);
Id elemId = buffer.readId();
if (index == null) {
index = Index.parseIndexId(graph, indexType, indexId.asBytes());
}
long expiredTime = 0L;
if (indexCol.value.length > 0) {
// Get delimiter address
int delimiterIndex =
Bytes.indexOf(indexCol.value, BytesBuffer.STRING_ENDING_BYTE);
if (delimiterIndex >= 0) {
// Delimiter is in the data, need to parse from data
// 1. field value real content
byte[] fieldValueBytes =
Arrays.copyOfRange(indexCol.value, 0, delimiterIndex);
if (fieldValueBytes.length > 0) {
index.fieldValues(StringEncoding.decode(fieldValueBytes));
}
// 2. Expiration time
byte[] expiredTimeBytes =
Arrays.copyOfRange(indexCol.value, delimiterIndex + 1,
indexCol.value.length);
if (expiredTimeBytes.length > 0) {
byte[] rawBytes =
Base64.getDecoder().decode(expiredTimeBytes);
if (rawBytes.length >= Longs.BYTES) {
expiredTime = Longs.fromByteArray(rawBytes);
}
}
} else {
// Only field value data
index.fieldValues(StringEncoding.decode(indexCol.value));
}
}
index.elementIds(elemId, expiredTime);
return index;
}
public BackendColumn parseIndex(BackendColumn indexCol) {
// Self-parsing index
throw new NotImplementedException(
"BinaryElementSerializer.parseIndex");
}
public BackendColumn writeVertex(BaseVertex vertex) {
if (vertex.olap()) {
return this.writeOlapVertex(vertex);
}
BytesBuffer bufferName = BytesBuffer.allocate(vertex.id().length());
bufferName.writeId(vertex.id());
int propsCount = vertex.getProperties().size();
BytesBuffer buffer = BytesBuffer.allocate(8 + 16 * propsCount);
// Write vertex label
buffer.writeId(vertex.schemaLabel().id());
// Write all properties of the vertex
this.formatProperties(vertex.getProperties().values(), buffer);
// Write vertex expired time if needed
if (vertex.hasTtl()) {
this.formatExpiredTime(vertex.expiredTime(), buffer);
}
return BackendColumn.of(bufferName.bytes(), buffer.bytes());
}
public BackendColumn writeOlapVertex(BaseVertex vertex) {
BytesBuffer buffer = BytesBuffer.allocate(8 + 16);
BaseProperty<?> baseProperty = vertex.getProperties().values()
.iterator().next();
PropertyKey propertyKey = baseProperty.propertyKey();
buffer.writeVInt(SchemaElement.schemaId(propertyKey.id()));
buffer.writeProperty(propertyKey.cardinality(), propertyKey.dataType(),
baseProperty.value());
// OLAP table merge, key is {property_key_id}{vertex_id}
BytesBuffer bufferName =
BytesBuffer.allocate(1 + propertyKey.id().length() + 1 +
vertex.id().length());
bufferName.writeId(propertyKey.id());
bufferName.writeId(vertex.id()).bytes();
return BackendColumn.of(bufferName.bytes(), buffer.bytes());
}
public BackendColumn writeEdge(BaseEdge edge) {
byte[] name = this.formatEdgeName(edge);
byte[] value = this.formatEdgeValue(edge);
return BackendColumn.of(name, value);
}
/**
* Convert an index data to a BackendColumn
*/
public BackendColumn writeIndex(Index index) {
return BackendColumn.of(formatIndexName(index),
formatIndexValue(index));
}
private byte[] formatIndexName(Index index) {
BytesBuffer buffer;
Id elemId = index.elementId();
Id indexId = index.id();
HugeType type = index.type();
int idLen = 1 + elemId.length() + 1 + indexId.length();
buffer = BytesBuffer.allocate(idLen);
// Write index-id
buffer.writeIndexId(indexId, type);
// Write element-id
buffer.writeId(elemId);
return buffer.bytes();
}
/**
* @param index value
* @return format
* | empty(field-value) | 0x00 | base64(expiredtime) |
*/
private byte[] formatIndexValue(Index index) {
if (index.hasTtl()) {
BytesBuffer valueBuffer = BytesBuffer.allocate(14);
valueBuffer.write(BytesBuffer.STRING_ENDING_BYTE);
byte[] ttlBytes =
Base64.getEncoder().encode(Longs.toByteArray(index.expiredTime()));
valueBuffer.write(ttlBytes);
return valueBuffer.bytes();
}
return null;
}
public BackendColumn mergeCols(BackendColumn vertexCol, BackendColumn... olapVertexCols) {
if (olapVertexCols.length == 0) {
return vertexCol;
}
BytesBuffer mergedBuffer = BytesBuffer.allocate(
vertexCol.value.length + olapVertexCols.length * 16);
BytesBuffer buffer = BytesBuffer.wrap(vertexCol.value);
Id vl = buffer.readId();
int size = buffer.readVInt();
mergedBuffer.writeId(vl);
mergedBuffer.writeVInt(size + olapVertexCols.length);
// Prioritize writing vertexCol properties, because vertexCol may contain TTL
for (BackendColumn olapVertexCol : olapVertexCols) {
mergedBuffer.write(olapVertexCol.value);
}
mergedBuffer.write(buffer.remainingBytes());
return BackendColumn.of(vertexCol.name, mergedBuffer.bytes());
}
public BaseElement index2Element(HugeGraphSupplier graph,
BackendColumn indexCol) {
throw new NotImplementedException(
"BinaryElementSerializer.index2Element");
}
public byte[] formatEdgeName(BaseEdge edge) {
// owner-vertex + dir + edge-label + sort-values + other-vertex
return BytesBuffer.allocate(BytesBuffer.BUF_EDGE_ID)
.writeEdgeId(edge.id()).bytes();
}
protected byte[] formatEdgeValue(BaseEdge edge) {
Map<Id, BaseProperty<?>> properties = edge.getProperties();
int propsCount = properties.size();
BytesBuffer buffer = BytesBuffer.allocate(4 + 16 * propsCount);
// Write edge properties
this.formatProperties(properties.values(), buffer);
// Write edge expired time if needed
if (edge.hasTtl()) {
this.formatExpiredTime(edge.expiredTime(), buffer);
}
return buffer.bytes();
}
public void formatProperties(Collection<BaseProperty<?>> props,
BytesBuffer buffer) {
// Write properties size
buffer.writeVInt(props.size());
// Write properties data
for (BaseProperty<?> property : props) {
PropertyKey pkey = property.propertyKey();
buffer.writeVInt(SchemaElement.schemaId(pkey.id()));
buffer.writeProperty(pkey.cardinality(), pkey.dataType(),
property.value());
}
}
public void formatExpiredTime(long expiredTime, BytesBuffer buffer) {
buffer.writeVLong(expiredTime);
}
protected void parseExpiredTime(BytesBuffer buffer, BaseElement element) {
element.expiredTime(buffer.readVLong());
}
private HugeType parseIndexType(BackendColumn col) {
/**
* Reference formatIndexName method
* For range type index, col.name first byte writes type.code (1 byte)
* Other type indexes will write type.name in first two bytes (2 byte)
*/
byte first = col.name[0];
byte second = col.name[1];
if (first < 0) {
return HugeType.fromCode(first);
}
assert second >= 0;
String type = new String(new byte[]{first, second});
return HugeType.fromString(type);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,128 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.serializer;
import java.util.Arrays;
import java.util.Base64;
import org.apache.hugegraph.util.Bytes;
import org.apache.hugegraph.util.Log;
import org.slf4j.Logger;
import org.apache.hugegraph.id.Id;
import org.apache.hugegraph.id.IdGenerator;
import org.apache.hugegraph.schema.PropertyKey;
import com.google.common.primitives.Longs;
public class DirectBinarySerializer {
protected static final Logger LOG = Log.logger(DirectBinarySerializer.class);
public static class DirectHugeElement {
private Id id;
private long expiredTime;
public DirectHugeElement(Id id, long expiredTime) {
this.id = id;
this.expiredTime = expiredTime;
}
public Id id() {
return id;
}
public long expiredTime() {
return expiredTime;
}
}
public DirectHugeElement parseIndex(byte[] key, byte[] value) {
long expiredTime = 0L;
if (value.length > 0) {
// Get delimiter address
int delimiterIndex =
Bytes.indexOf(value, BytesBuffer.STRING_ENDING_BYTE);
if (delimiterIndex >= 0) {
// Delimiter is in the data, need to parse from data
// Parse expiration time
byte[] expiredTimeBytes =
Arrays.copyOfRange(value, delimiterIndex + 1,
value.length);
if (expiredTimeBytes.length > 0) {
byte[] rawBytes =
Base64.getDecoder().decode(expiredTimeBytes);
if (rawBytes.length >= Longs.BYTES) {
expiredTime = Longs.fromByteArray(rawBytes);
}
}
}
}
return new DirectHugeElement(IdGenerator.of(key), expiredTime);
}
public DirectHugeElement parseVertex(byte[] key, byte[] value) {
long expiredTime = 0L;
BytesBuffer buffer = BytesBuffer.wrap(value);
// read schema label id
buffer.readId();
// Skip edge properties
this.skipProperties(buffer);
// Parse edge expired time if needed
if (buffer.remaining() > 0) {
expiredTime = buffer.readVLong();
}
return new DirectHugeElement(IdGenerator.of(key), expiredTime);
}
public DirectHugeElement parseEdge(byte[] key, byte[] value) {
long expiredTime = 0L;
BytesBuffer buffer = BytesBuffer.wrap(value);
// Skip edge properties
this.skipProperties(buffer);
// Parse edge expired time if needed
if (buffer.remaining() > 0) {
expiredTime = buffer.readVLong();
}
return new DirectHugeElement(IdGenerator.of(key), expiredTime);
}
private void skipProperties(BytesBuffer buffer) {
int size = buffer.readVInt();
assert size >= 0;
for (int i = 0; i < size; i++) {
Id pkeyId = IdGenerator.of(buffer.readVInt());
this.skipProperty(pkeyId, buffer);
}
}
protected void skipProperty(Id pkeyId, BytesBuffer buffer) {
// Parse value
PropertyKey pkey = new PropertyKey(null, pkeyId, "");
buffer.readProperty(pkey);
}
}

View File

@ -0,0 +1,288 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.structure;
import org.apache.hugegraph.HugeGraphSupplier;
import org.apache.hugegraph.exception.HugeException;
import org.apache.hugegraph.id.EdgeId;
import org.apache.hugegraph.id.Id;
import org.apache.hugegraph.id.SplicingIdGenerator;
import org.apache.hugegraph.schema.EdgeLabel;
import org.apache.hugegraph.schema.SchemaLabel;
import org.apache.hugegraph.schema.VertexLabel;
import org.apache.hugegraph.serializer.BytesBuffer;
import org.apache.hugegraph.type.HugeType;
import org.apache.hugegraph.type.define.Directions;
import org.apache.hugegraph.type.define.HugeKeys;
import com.google.common.collect.ImmutableList;
import org.apache.hugegraph.util.E;
import java.util.ArrayList;
import java.util.List;
/* Only as basic data container, id generation logic relies on upper layer encapsulation*/
public class BaseEdge extends BaseElement implements Cloneable {
private BaseVertex sourceVertex;
private BaseVertex targetVertex;
boolean isOutEdge;
private String name;
public BaseEdge(Id id, EdgeLabel label) {
this.id(id);
this.schemaLabel(label);
}
public BaseEdge(SchemaLabel label, boolean isOutEdge) {
this.schemaLabel(label);
this.isOutEdge = isOutEdge;
}
public boolean isOutEdge() {
return isOutEdge;
}
public void isOutEdge(boolean isOutEdge) {
this.isOutEdge = isOutEdge;
}
public EdgeId idWithDirection() {
return ((EdgeId) this.id()).directed(true);
}
@Override
public String name() {
if (this.name == null) {
this.name = SplicingIdGenerator.concatValues(sortValues());
}
return this.name;
}
public void name(String name) {
this.name = name;
}
@Override
public HugeType type() {
// NOTE: we optimize the edge type that let it include direction
return this.isOutEdge() ? HugeType.EDGE_OUT : HugeType.EDGE_IN;
}
public List<Object> sortValues() {
List<Id> sortKeys = this.schemaLabel().sortKeys();
if (sortKeys.isEmpty()) {
return ImmutableList.of();
}
List<Object> propValues = new ArrayList<>(sortKeys.size());
for (Id sk : sortKeys) {
BaseProperty<?> property = this.getProperty(sk);
E.checkState(property != null,
"The value of sort key '%s' can't be null", sk);
propValues.add(property.propertyKey().serialValue(property.value(), true));
}
return propValues;
}
public Directions direction() {
return this.isOutEdge ? Directions.OUT : Directions.IN;
}
public Id sourceVertexId() {
return this.sourceVertex.id();
}
public Id targetVertexId() {
return this.targetVertex.id();
}
public void sourceVertex(BaseVertex sourceVertex) {
this.sourceVertex = sourceVertex;
}
public BaseVertex sourceVertex() {
return this.sourceVertex;
}
public void targetVertex(BaseVertex targetVertex) {
this.targetVertex = targetVertex;
}
public BaseVertex targetVertex() {
return this.targetVertex;
}
public Id ownerVertexId() {
return this.isOutEdge() ? this.sourceVertexId() : this.targetVertexId();
}
public Id otherVertexId() {
return this.isOutEdge() ? this.targetVertexId() : this.sourceVertexId() ;
}
public void vertices(boolean outEdge, BaseVertex owner, BaseVertex other) {
this.isOutEdge = outEdge ;
if (outEdge) {
this.sourceVertex(owner);
this.targetVertex(other);
} else {
this.sourceVertex(other);
this.targetVertex(owner);
}
}
public EdgeLabel schemaLabel() {
return (EdgeLabel) super.schemaLabel();
}
public BaseVertex ownerVertex() {
return this.isOutEdge() ? this.sourceVertex() : this.targetVertex();
}
public BaseVertex otherVertex() {
return this.isOutEdge() ? this.targetVertex() : this.sourceVertex();
}
public void assignId() {
// Generate an id and assign
if (this.schemaLabel().hasFather()) {
this.id(new EdgeId(this.ownerVertex().id(), this.direction(),
this.schemaLabel().fatherId(),
this.schemaLabel().id(),
this.name(),
this.otherVertex().id()));
} else {
this.id(new EdgeId(this.ownerVertex().id(), this.direction(),
this.schemaLabel().id(),
this.schemaLabel().id(),
this.name(), this.otherVertex().id()));
}
if (this.fresh()) {
int len = this.id().length();
E.checkArgument(len <= BytesBuffer.BIG_ID_LEN_MAX,
"The max length of edge id is %s, but got %s {%s}",
BytesBuffer.BIG_ID_LEN_MAX, len, this.id());
}
}
@Override
public Object sysprop(HugeKeys key) {
switch (key) {
case ID:
return this.id();
case OWNER_VERTEX:
return this.ownerVertexId();
case LABEL:
if (this.schemaLabel().fatherId() != null) {
return this.schemaLabel().fatherId();
} else {
return this.schemaLabel().id();
}
case DIRECTION:
return this.direction();
case SUB_LABEL:
return this.schemaLabel().id();
case OTHER_VERTEX:
return this.otherVertexId();
case SORT_VALUES:
return this.name();
case PROPERTIES:
return this.getPropertiesMap();
default:
E.checkArgument(false,
"Invalid system property '%s' of Edge", key);
return null;
}
}
@Override
public BaseEdge clone() {
try {
return (BaseEdge) super.clone();
} catch (CloneNotSupportedException e) {
throw new HugeException("Failed to clone HugeEdge", e);
}
}
public BaseEdge switchOwner() {
BaseEdge edge = this.clone();
edge.isOutEdge(!edge.isOutEdge());
if (edge.id() != null) {
edge.id(((EdgeId) edge.id()).switchDirection());
}
return edge;
}
public static BaseEdge constructEdge(HugeGraphSupplier graph,
BaseVertex ownerVertex,
boolean isOutEdge,
EdgeLabel edgeLabel,
String sortValues,
Id otherVertexId) {
Id ownerLabelId = edgeLabel.sourceLabel();
Id otherLabelId = edgeLabel.targetLabel();
VertexLabel srcLabel;
VertexLabel tgtLabel;
if (graph == null) {
srcLabel = new VertexLabel(null, ownerLabelId, "UNDEF");
tgtLabel = new VertexLabel(null, otherLabelId, "UNDEF");
} else {
if (edgeLabel.general()) {
srcLabel = VertexLabel.GENERAL;
tgtLabel = VertexLabel.GENERAL;
} else {
srcLabel = graph.vertexLabelOrNone(ownerLabelId);
tgtLabel = graph.vertexLabelOrNone(otherLabelId);
}
}
VertexLabel otherVertexLabel;
if (isOutEdge) {
ownerVertex.correctVertexLabel(srcLabel);
otherVertexLabel = tgtLabel;
} else {
ownerVertex.correctVertexLabel(tgtLabel);
otherVertexLabel = srcLabel;
}
BaseVertex otherVertex = new BaseVertex(otherVertexId, otherVertexLabel);
ownerVertex.propLoaded(false);
otherVertex.propLoaded(false);
BaseEdge edge = new BaseEdge(edgeLabel, isOutEdge);
edge.name(sortValues);
edge.vertices(isOutEdge, ownerVertex, otherVertex);
edge.assignId();
ownerVertex.addEdge(edge);
otherVertex.addEdge(edge.switchOwner());
return edge;
}
}

View File

@ -0,0 +1,355 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.structure;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;
import org.apache.hugegraph.util.CollectionUtil;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.Log;
import org.eclipse.collections.api.map.primitive.MutableIntObjectMap;
import org.eclipse.collections.api.tuple.primitive.IntObjectPair;
import org.eclipse.collections.impl.map.mutable.primitive.IntObjectHashMap;
import org.slf4j.Logger;
import org.apache.hugegraph.id.Id;
import org.apache.hugegraph.id.IdGenerator;
import org.apache.hugegraph.schema.PropertyKey;
import org.apache.hugegraph.schema.SchemaLabel;
import org.apache.hugegraph.serializer.BytesBuffer;
import org.apache.hugegraph.type.GraphType;
import org.apache.hugegraph.type.Idfiable;
import org.apache.hugegraph.type.define.Cardinality;
import org.apache.hugegraph.type.define.HugeKeys;
import org.apache.hugegraph.util.collection.CollectionFactory;
public abstract class BaseElement implements GraphType, Idfiable, Serializable {
private static final Logger LOG = Log.logger(BaseElement.class);
public static final MutableIntObjectMap<BaseProperty<?>> EMPTY_MAP =
new IntObjectHashMap<>();
private static final int MAX_PROPERTIES = BytesBuffer.UINT16_MAX;
MutableIntObjectMap<BaseProperty<?>> properties;
Id id;
private SchemaLabel schemaLabel;
long expiredTime; // TODO: move into properties to keep small object
private boolean removed;
private boolean fresh;
private boolean propLoaded;
private boolean defaultValueUpdated;
public BaseElement() {
this.properties = EMPTY_MAP;
this.removed = false;
this.fresh = false;
this.propLoaded = true;
this.defaultValueUpdated = false;
}
public void setProperties(MutableIntObjectMap<BaseProperty<?>> properties) {
this.properties = properties;
}
public Id id(){
return id;
}
public void id(Id id) {
this.id = id;
}
public boolean removed() {
return removed;
}
public void removed(boolean removed) {
this.removed = removed;
}
public boolean fresh() {
return fresh;
}
public void fresh(boolean fresh) {
this.fresh = fresh;
}
public boolean propLoaded() {
return propLoaded;
}
public void propLoaded(boolean propLoaded) {
this.propLoaded = propLoaded;
}
public boolean defaultValueUpdated() {
return defaultValueUpdated;
}
public void defaultValueUpdated(boolean defaultValueUpdated) {
this.defaultValueUpdated = defaultValueUpdated;
}
public SchemaLabel schemaLabel() {
return schemaLabel;
}
public void schemaLabel(SchemaLabel label) {
this.schemaLabel = label;
}
public long expiredTime() {
return expiredTime;
}
public void expiredTime(long expiredTime) {
this.expiredTime = expiredTime;
}
public boolean hasTtl() {
return this.schemaLabel.ttl() > 0L;
}
public boolean expired(long now) {
boolean expired;
SchemaLabel label = this.schemaLabel();
if (label.ttl() == 0L) {
// No ttl, not expired
return false;
}
if (this.expiredTime() > 0L) {
// Has ttl and set expiredTime properly
expired = this.expiredTime() < now;
LOG.debug("The element {} {} with expired time {} and now {}",
this, expired ? "expired" : "not expired",
this.expiredTime(), now);
return expired;
}
// Has ttl, but failed to set expiredTime when insert
LOG.error("The element {} should have positive expired time, " +
"but got {}! ttl is {} ttl start time is {}",
this, this.expiredTime(), label.ttl(), label.ttlStartTimeName());
if (SchemaLabel.NONE_ID.equals(label.ttlStartTime())) {
// No ttlStartTime, can't decide whether timeout, treat not expired
return false;
}
Date date = this.getPropertyValue(label.ttlStartTime());
if (date == null) {
// No ttlStartTime, can't decide whether timeout, treat not expired
return false;
}
// Has ttlStartTime, re-calc expiredTime to decide whether timeout,
long expiredTime = date.getTime() + label.ttl();
expired = expiredTime < now;
LOG.debug("The element {} {} with expired time {} and now {}",
this, expired ? "expired" : "not expired",
expiredTime, now);
return expired;
}
public long ttl(long now) {
if (this.expiredTime() == 0L || this.expiredTime() < now) {
return 0L;
}
return this.expiredTime() - now;
}
protected <V> BaseProperty<V> newProperty(PropertyKey pkey, V val) {
return new BaseProperty<>(pkey, val);
}
public boolean hasProperty(Id key) {
return this.properties.containsKey(intFromId(key));
}
public boolean hasProperties() {
return this.properties.size() > 0;
}
public void setExpiredTimeIfNeeded(long now) {
SchemaLabel label = this.schemaLabel();
if (label.ttl() == 0L) {
return;
}
if (SchemaLabel.NONE_ID.equals(label.ttlStartTime())) {
this.expiredTime(now + label.ttl());
return;
}
Date date = this.getPropertyValue(label.ttlStartTime());
if (date == null) {
this.expiredTime(now + label.ttl());
return;
}
long expired = date.getTime() + label.ttl();
E.checkArgument(expired > now,
"The expired time '%s' of '%s' is prior to now: %s",
new Date(expired), this, now);
this.expiredTime(expired);
}
public void resetProperties() {
this.properties = CollectionFactory.newIntObjectMap();
this.propLoaded(true);
}
public <V> V getPropertyValue(Id key) {
BaseProperty<?> prop = this.properties.get(intFromId(key));
if (prop == null) {
return null;
}
return (V) prop.value();
}
public MutableIntObjectMap<BaseProperty<?>> properties() {
return this.properties;
}
public void properties(MutableIntObjectMap<BaseProperty<?>> properties) {
this.properties = properties;
}
public <V> BaseProperty<V> getProperty(Id key) {
return (BaseProperty<V>) this.properties.get(intFromId(key));
}
private <V> BaseProperty<V> addProperty(PropertyKey pkey, V value,
Supplier<Collection<V>> supplier) {
assert pkey.cardinality().multiple();
BaseProperty<Collection<V>> property;
if (this.hasProperty(pkey.id())) {
property = this.getProperty(pkey.id());
} else {
property = this.newProperty(pkey, supplier.get());
this.addProperty(property);
}
Collection<V> values;
if (pkey.cardinality() == Cardinality.SET) {
if (value instanceof Set) {
values = (Set<V>) value;
} else {
values = CollectionUtil.toSet(value);
}
} else {
assert pkey.cardinality() == Cardinality.LIST;
if (value instanceof List) {
values = (List<V>) value;
} else {
values = CollectionUtil.toList(value);
}
}
property.value().addAll(values);
// Any better ways?
return (BaseProperty) property;
}
public <V> BaseProperty<V> addProperty(PropertyKey pkey, V value) {
BaseProperty<V> prop = null;
switch (pkey.cardinality()) {
case SINGLE:
prop = this.newProperty(pkey, value);
this.addProperty(prop);
break;
case SET:
prop = this.addProperty(pkey, value, HashSet::new);
break;
case LIST:
prop = this.addProperty(pkey, value, ArrayList::new);
break;
default:
assert false;
break;
}
return prop;
}
public <V> BaseProperty<?> addProperty(BaseProperty<V> prop) {
if (this.properties == EMPTY_MAP) {
this.properties = new IntObjectHashMap<>(); // change to CollectionFactory.newIntObjectMap();
}
PropertyKey pkey = prop.propertyKey();
E.checkArgument(this.properties.containsKey(intFromId(pkey.id())) ||
this.properties.size() < MAX_PROPERTIES,
"Exceeded the maximum number of properties");
return this.properties.put(intFromId(pkey.id()), prop);
}
public Map<Id, BaseProperty<?>> getProperties() {
Map<Id, BaseProperty<?>> props = new HashMap<>();
for (IntObjectPair<BaseProperty<?>> e : this.properties.keyValuesView()) {
props.put(IdGenerator.of(e.getOne()), e.getTwo());
}
return props;
}
public <V> BaseProperty<?> removeProperty(Id key) {
return this.properties.remove(intFromId(key));
}
/* a util may be should be moved to other place */
public static int intFromId(Id id) {
E.checkArgument(id instanceof IdGenerator.LongId,
"Can't get number from %s(%s)", id, id.getClass());
return ((IdGenerator.LongId) id).intValue();
}
public abstract Object sysprop(HugeKeys key);
public Map<Id, Object> getPropertiesMap() {
Map<Id, Object> props = new HashMap<>();
for (IntObjectPair<BaseProperty<?>> e : this.properties.keyValuesView()) {
props.put(IdGenerator.of(e.getOne()), e.getTwo().value());
}
return props;
}
public int sizeOfProperties() {
return this.properties.size();
}
public int sizeOfSubProperties() {
int size = 0;
for (BaseProperty<?> p : this.properties.values()) {
size++;
if (p.propertyKey().cardinality() != Cardinality.SINGLE &&
p.value() instanceof Collection) {
size += ((Collection<?>) p.value()).size();
}
}
return size;
}
@Override
public BaseElement clone() throws CloneNotSupportedException{
return (BaseElement) super.clone();
}
}

View File

@ -0,0 +1,68 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.structure;
import org.apache.hugegraph.schema.PropertyKey;
import org.apache.hugegraph.type.define.Cardinality;
import org.apache.hugegraph.type.define.DataType;
public class BaseProperty<V> {
private PropertyKey propertyKey;
protected V value;
public BaseProperty(PropertyKey propertyKey, V value) {
this.propertyKey = propertyKey;
this.value = value;
}
public DataType getDataType() {
return propertyKey.dataType();
}
public void setDataType(DataType dataType) {
this.propertyKey.dataType(dataType);
}
public Cardinality getCardinality() {
return propertyKey.cardinality();
}
public void setCardinality(Cardinality cardinality) {
this.propertyKey.cardinality(cardinality);
}
public V value() {
return value;
}
public void value(V value) {
this.value = value;
}
public PropertyKey propertyKey() {
return propertyKey;
}
public Object serialValue(boolean encodeNumber) {
return this.propertyKey.serialValue(this.value, encodeNumber);
}
}

View File

@ -0,0 +1,57 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.structure;
import org.apache.hugegraph.type.HugeType;
import org.apache.hugegraph.type.define.HugeKeys;
public class BaseRawElement extends BaseElement implements Cloneable {
private byte[] key;
private byte[] value;
public BaseRawElement(byte[] key, byte[] value) {
this.key = key;
this.value = value;
}
public byte[] key() {
return this.key;
}
public byte[] value() {
return this.value;
}
@Override
public Object sysprop(HugeKeys key) {
return null;
}
@Override
public String name() {
return null;
}
@Override
public HugeType type() {
return HugeType.KV_RAW;
}
}

View File

@ -0,0 +1,168 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.structure;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.apache.hugegraph.perf.PerfUtil;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.id.Id;
import org.apache.hugegraph.id.SplicingIdGenerator;
import org.apache.hugegraph.schema.SchemaLabel;
import org.apache.hugegraph.schema.VertexLabel;
import org.apache.hugegraph.type.HugeType;
import org.apache.hugegraph.type.define.CollectionType;
import org.apache.hugegraph.type.define.HugeKeys;
import org.apache.hugegraph.type.define.IdStrategy;
import org.apache.hugegraph.util.collection.CollectionFactory;
import com.google.common.collect.ImmutableList;
public class BaseVertex extends BaseElement implements Cloneable {
private static final List<BaseEdge> EMPTY_LIST = ImmutableList.of();
protected Collection<BaseEdge> edges;
public BaseVertex(Id id) {
this.edges = EMPTY_LIST;
id(id);
}
public BaseVertex(Id id, SchemaLabel label) {
// Note:
// If vertex is OLAP Vertex, id is the id of the vertex that the olap property belongs to, not including the olap property id.
this(id);
this.schemaLabel(label);
}
@Override
public String name() {
E.checkState(this.schemaLabel().idStrategy() == IdStrategy.PRIMARY_KEY,
"Only primary key vertex has name, " +
"but got '%s' with id strategy '%s'",
this, this.schemaLabel().idStrategy());
String name;
if (this.id() != null) {
String[] parts = SplicingIdGenerator.parse(this.id());
E.checkState(parts.length == 2,
"Invalid primary key vertex id '%s'", this.id());
name = parts[1];
} else {
assert this.id() == null;
List<Object> propValues = this.primaryValues();
E.checkState(!propValues.isEmpty(),
"Primary values must not be empty " +
"(has properties %s)", hasProperties());
name = SplicingIdGenerator.concatValues(propValues);
E.checkArgument(!name.isEmpty(),
"The value of primary key can't be empty");
}
return name;
}
@PerfUtil.Watched(prefix = "vertex")
public List<Object> primaryValues() {
E.checkArgument(this.schemaLabel().idStrategy() == IdStrategy.PRIMARY_KEY,
"The id strategy '%s' don't have primary keys",
this.schemaLabel().idStrategy());
List<Id> primaryKeys = this.schemaLabel().primaryKeys();
E.checkArgument(!primaryKeys.isEmpty(),
"Primary key can't be empty for id strategy '%s'",
IdStrategy.PRIMARY_KEY);
List<Object> propValues = new ArrayList<>(primaryKeys.size());
for (Id pk : primaryKeys) {
BaseProperty<?> property = this.getProperty(pk);
E.checkState(property != null,
"The value of primary key '%s' can't be null"
/*this.graph().propertyKey(pk).name() complete log*/);
propValues.add(property.serialValue(true));
}
return propValues;
}
public void addEdge(BaseEdge edge) {
if (this.edges == EMPTY_LIST) {
this.edges = CollectionFactory.newList(CollectionType.EC);
}
this.edges.add(edge);
}
public void correctVertexLabel(VertexLabel correctLabel) {
E.checkArgumentNotNull(correctLabel, "Vertex label can't be null");
if (this.schemaLabel() != null && !this.schemaLabel().undefined() &&
!correctLabel.undefined() && !this.schemaLabel().generalVl() && !correctLabel.generalVl()) {
E.checkArgument(this.schemaLabel().equals(correctLabel),
"[%s]'s Vertex label can't be changed from '%s' " +
"to '%s'", this.id(), this.schemaLabel(),
correctLabel);
}
this.schemaLabel(correctLabel);
}
public Collection<BaseEdge> edges() {
return this.edges;
}
public void edges(Collection<BaseEdge> edges) {
this.edges = edges;
}
@Override
public Object sysprop(HugeKeys key) {
switch (key) {
case ID:
return this.id();
case LABEL:
return this.schemaLabel().id();
case PRIMARY_VALUES:
return this.name();
case PROPERTIES:
return this.getPropertiesMap();
default:
E.checkArgument(false,
"Invalid system property '%s' of Vertex", key);
return null;
}
}
public VertexLabel schemaLabel() {
return (VertexLabel)super.schemaLabel();
}
public boolean olap() {
return VertexLabel.OLAP_VL.equals(this.schemaLabel());
}
public HugeType type() {
// For Vertex type, when label is task, return TASK type, convenient for getting storage table information based on type
/* Magic: ~task ~taskresult ~variables*/
if (schemaLabel() != null &&
(schemaLabel().name().equals("~task") ||
schemaLabel().name().equals("~taskresult") ||
schemaLabel().name().equals("~variables"))) {
return HugeType.TASK;
}
return HugeType.VERTEX;
}
}

View File

@ -0,0 +1,334 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.structure;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.InsertionOrderUtil;
import org.apache.hugegraph.util.NumericUtil;
import org.apache.hugegraph.HugeGraphSupplier;
import org.apache.hugegraph.exception.HugeException;
import org.apache.hugegraph.id.Id;
import org.apache.hugegraph.id.Id.IdType;
import org.apache.hugegraph.id.IdGenerator;
import org.apache.hugegraph.id.SplicingIdGenerator;
import org.apache.hugegraph.schema.IndexLabel;
import org.apache.hugegraph.schema.SchemaElement;
import org.apache.hugegraph.serializer.BytesBuffer;
import org.apache.hugegraph.type.GraphType;
import org.apache.hugegraph.type.HugeType;
import org.apache.hugegraph.type.define.DataType;
import com.google.common.collect.ImmutableSet;
public class Index implements GraphType, Cloneable {
private final HugeGraphSupplier graph;
private Object fieldValues;
private IndexLabel indexLabel;
/*
* Index read use elementIds, Index write always one element, use
* elementId
*/
private Set<IdWithExpiredTime> elementIds;
private IdWithExpiredTime elementId;
public Index(HugeGraphSupplier graph, IndexLabel indexLabel) {
E.checkNotNull(graph, "graph");
E.checkNotNull(indexLabel, "label");
E.checkNotNull(indexLabel.id(), "label id");
this.graph = graph;
this.indexLabel = indexLabel;
this.elementIds = new LinkedHashSet<>();
this.fieldValues = null;
}
public Index(HugeGraphSupplier graph, IndexLabel indexLabel, boolean write) {
E.checkNotNull(graph, "graph");
E.checkNotNull(indexLabel, "label");
E.checkNotNull(indexLabel.id(), "label id");
this.graph = graph;
this.indexLabel = indexLabel;
if (!write) {
this.elementIds = new LinkedHashSet<>();
}
this.elementId = null;
this.fieldValues = null;
}
@Override
public String name() {
return this.indexLabel.name();
}
@Override
public HugeType type() {
if (this.indexLabel == IndexLabel.label(HugeType.VERTEX)) {
return HugeType.VERTEX_LABEL_INDEX;
} else if (this.indexLabel == IndexLabel.label(HugeType.EDGE)) {
return HugeType.EDGE_LABEL_INDEX;
}
return this.indexLabel.indexType().type();
}
public HugeGraphSupplier graph() {
return this.graph;
}
public Id id() {
return formatIndexId(type(), this.indexLabelId(), this.fieldValues());
}
public Object fieldValues() {
return this.fieldValues;
}
public void fieldValues(Object fieldValues) {
this.fieldValues = fieldValues;
}
public Id indexLabelId() {
return this.indexLabel.id();
}
public IndexLabel indexLabel() {
return this.indexLabel;
}
public IdWithExpiredTime elementIdWithExpiredTime() {
if (this.elementIds == null) {
return this.elementId;
}
E.checkState(this.elementIds.size() == 1,
"Expect one element id, actual %s",
this.elementIds.size());
return this.elementIds.iterator().next();
}
public Id elementId() {
return this.elementIdWithExpiredTime().id();
}
public Set<Id> elementIds() {
if (this.elementIds == null) {
return ImmutableSet.of();
}
Set<Id> ids = InsertionOrderUtil.newSet(this.elementIds.size());
for (IdWithExpiredTime idWithExpiredTime : this.elementIds) {
ids.add(idWithExpiredTime.id());
}
return Collections.unmodifiableSet(ids);
}
public Set<IdWithExpiredTime> expiredElementIds() {
long now = this.graph.now();
Set<IdWithExpiredTime> expired = InsertionOrderUtil.newSet();
for (IdWithExpiredTime id : this.elementIds) {
if (0L < id.expiredTime && id.expiredTime < now) {
expired.add(id);
}
}
this.elementIds.removeAll(expired);
return expired;
}
public void elementIds(Id elementId) {
this.elementIds(elementId, 0L);
}
public void elementIds(Id elementId, long expiredTime) {
if (this.elementIds == null) {
this.elementId = new IdWithExpiredTime(elementId, expiredTime);
} else {
this.elementIds.add(new IdWithExpiredTime(elementId, expiredTime));
}
}
public void resetElementIds() {
this.elementIds = null;
}
public long expiredTime() {
return this.elementIdWithExpiredTime().expiredTime();
}
public boolean hasTtl() {
if ((this.indexLabel() == IndexLabel.label(HugeType.VERTEX) ||
this.indexLabel() == IndexLabel.label(HugeType.EDGE)) &&
this.expiredTime() > 0) {
// LabelIndex index, if element has expiration time, then index also has TTL
return true;
}
if (this.indexLabel.system()) {
return false;
}
return this.indexLabel.baseElement().ttl() > 0L;
}
public long ttl() {
return this.expiredTime() - this.graph.now();
}
@Override
public Index clone() {
try {
return (Index) super.clone();
} catch (CloneNotSupportedException e) {
throw new HugeException("Failed to clone Index", e);
}
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Index)) {
return false;
}
Index other = (Index) obj;
return this.id().equals(other.id());
}
@Override
public int hashCode() {
return this.id().hashCode();
}
@Override
public String toString() {
return String.format("{label=%s<%s>, fieldValues=%s, elementIds=%s}",
this.indexLabel.name(),
this.indexLabel.indexType().string(),
this.fieldValues, this.elementIds);
}
public static Id formatIndexId(HugeType type, Id indexLabelId,
Object fieldValues) {
if (type.isStringIndex()) {
String value = "";
if (fieldValues instanceof Id) {
value = IdGenerator.asStoredString((Id) fieldValues);
} else if (fieldValues != null) {
value = fieldValues.toString();
}
/*
* Modify order between index label and field-values to put the
* index label in front(hugegraph-1317)
*/
String strIndexLabelId = IdGenerator.asStoredString(indexLabelId);
// Add id prefix according to type
return SplicingIdGenerator.splicing(type.string(), strIndexLabelId, value);
} else {
assert type.isRangeIndex();
int length = type.isRange4Index() ? 4 : 8;
// 1 is table type, 4 is labelId, length is value
BytesBuffer buffer = BytesBuffer.allocate(1 + 4 + length);
// Add table type id
buffer.write(type.code());
buffer.writeInt(SchemaElement.schemaId(indexLabelId));
if (fieldValues != null) {
E.checkState(fieldValues instanceof Number,
"Field value of range index must be number:" +
" %s", fieldValues.getClass().getSimpleName());
byte[] bytes = number2bytes((Number) fieldValues);
buffer.write(bytes);
}
return buffer.asId();
}
}
public static Index parseIndexId(HugeGraphSupplier graph, HugeType type,
byte[] id) {
Object values;
IndexLabel indexLabel;
if (type.isStringIndex()) {
Id idObject = IdGenerator.of(id, IdType.STRING);
String[] parts = SplicingIdGenerator.parse(idObject);
E.checkState(parts.length == 3, "Invalid secondary index id");
Id label = IdGenerator.ofStoredString(parts[1], IdType.LONG);
indexLabel = IndexLabel.label(graph, label);
values = parts[2];
} else {
assert type.isRange4Index() || type.isRange8Index();
final int labelLength = 4;
E.checkState(id.length > labelLength, "Invalid range index id");
BytesBuffer buffer = BytesBuffer.wrap(id);
// Read the first byte representing the table type
final int hugeTypeCodeLength = 1;
byte[] read = buffer.read(hugeTypeCodeLength);
Id label = IdGenerator.of(buffer.readInt());
indexLabel = IndexLabel.label(graph, label);
List<Id> fields = indexLabel.indexFields();
E.checkState(fields.size() == 1, "Invalid range index fields");
DataType dataType = graph.propertyKey(fields.get(0)).dataType();
E.checkState(dataType.isNumber() || dataType.isDate(),
"Invalid range index field type");
Class<?> clazz = dataType.isNumber() ?
dataType.clazz() : DataType.LONG.clazz();
values = bytes2number(buffer.read(id.length - labelLength - hugeTypeCodeLength), clazz);
}
Index index = new Index(graph, indexLabel);
index.fieldValues(values);
return index;
}
public static byte[] number2bytes(Number number) {
if (number instanceof Byte) {
// Handle byte as integer to store as 4 bytes in RANGE4_INDEX
number = number.intValue();
}
return NumericUtil.numberToSortableBytes(number);
}
public static Number bytes2number(byte[] bytes, Class<?> clazz) {
return NumericUtil.sortableBytesToNumber(bytes, clazz);
}
public static class IdWithExpiredTime {
private Id id;
private long expiredTime;
public IdWithExpiredTime(Id id, long expiredTime) {
this.id = id;
this.expiredTime = expiredTime;
}
public Id id() {
return this.id;
}
public long expiredTime() {
return this.expiredTime;
}
@Override
public String toString() {
return String.format("%s(%s)", this.id, this.expiredTime);
}
}
}

View File

@ -0,0 +1,101 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.structure;
import java.util.List;
import org.apache.hugegraph.type.HugeType;
import org.apache.hugegraph.type.define.HugeKeys;
/**
* for aggregation calculation
*/
public class KvElement extends BaseElement implements Comparable<KvElement>{
private List<Comparable> keys;
private List<Object> values;
private KvElement(List<Comparable> keys, List<Object> values) {
this.keys = keys;
this.values = values;
}
public static KvElement of (List<Comparable> keys, List<Object> values) {
return new KvElement(keys, values);
}
public List<Comparable> getKeys() {
return keys;
}
public List<Object> getValues() {
return values;
}
@Override
public Object sysprop(HugeKeys key) {
return null;
}
@Override
public String name() {
return null;
}
@Override
public HugeType type() {
return HugeType.KV_TYPE;
}
/**
* compare by keys
* @param other the object to be compared.
* @return -1 = this > other, 0 = this == other, 1 = this < other.
*/
@Override
public int compareTo(KvElement other) {
if (this == other) {
return 0;
}
if (other == null || other.keys == null) {
return keys == null ? 0 : 1;
}
int len = Math.min(keys.size(), other.keys.size());
for (int i = 0; i < len; i++) {
var o1 = keys.get(i);
var o2 = other.keys.get(i);
if (o1 != o2) {
if (o1 == null || o2 == null) {
return o1 == null ? -1 : 1;
}
int v = o1.compareTo(o2);
if (v != 0) {
return v;
}
}
}
return keys.size() - other.keys.size();
}
}

View File

@ -0,0 +1,327 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.structure.builder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.apache.hugegraph.HugeGraphSupplier;
import org.apache.hugegraph.analyzer.Analyzer;
import org.apache.hugegraph.analyzer.AnalyzerFactory;
import org.apache.hugegraph.id.Id;
import org.apache.hugegraph.query.ConditionQuery;
import org.apache.hugegraph.schema.EdgeLabel;
import org.apache.hugegraph.schema.IndexLabel;
import org.apache.hugegraph.schema.SchemaLabel;
import org.apache.hugegraph.schema.VertexLabel;
import org.apache.hugegraph.structure.BaseEdge;
import org.apache.hugegraph.structure.BaseElement;
import org.apache.hugegraph.structure.BaseProperty;
import org.apache.hugegraph.structure.BaseVertex;
import org.apache.hugegraph.structure.Index;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.Log;
import org.apache.hugegraph.util.NumericUtil;
import org.slf4j.Logger;
public class IndexBuilder {
private static final Logger LOG = Log.logger(IndexBuilder.class);
private final HugeGraphSupplier graph;
private final Analyzer textAnalyzer;
public static final String INDEX_SYM_NULL = "\u0001";
public static final String INDEX_SYM_EMPTY = "\u0002";
public static final char INDEX_SYM_MAX = '\u0003';
private static final String TEXT_ANALYZER = "search.text_analyzer";
private static final String TEXT_ANALYZER_MODE =
"search.text_analyzer_mode";
private static final String DEFAULT_TEXT_ANALYZER = "ikanalyzer";
private static final String DEFAULT_TEXT_ANALYZER_MODE = "smart";
public IndexBuilder(HugeGraphSupplier graph) {
this.graph = graph;
String name = graph.configuration().get(String.class, TEXT_ANALYZER);
String mode = graph.configuration().get(String.class,
TEXT_ANALYZER_MODE);
name = name == null ? DEFAULT_TEXT_ANALYZER : name;
mode = mode == null ? DEFAULT_TEXT_ANALYZER_MODE : mode;
LOG.debug("Loading text analyzer '{}' with mode '{}' for graph '{}'",
name, mode, graph.name());
this.textAnalyzer = AnalyzerFactory.analyzer(name, mode);
}
public List<Index> buildLabelIndex(BaseElement element) {
List<Index> indexList = new ArrayList<Index>();
// Don't Build label index if it's not enabled
SchemaLabel label = element.schemaLabel();
// Build label index if backend store not supports label-query
Index index = new Index(graph,
IndexLabel.label(element.type()),
true);
index.fieldValues(element.schemaLabel().id());
index.elementIds(element.id(), element.expiredTime());
indexList.add(index);
/**When adding a sub-type edge, put its edgeID into the parent type's edgeLabelIndex at the same time
* to support: g.E().hasLabel("parent type")
* */
if (element instanceof BaseEdge && ((EdgeLabel) label).hasFather()) {
Index fatherIndex = new Index(graph,
IndexLabel.label(element.type()));
fatherIndex.fieldValues(((EdgeLabel) label).fatherId());
fatherIndex.elementIds(element.id(), element.expiredTime());
indexList.add(fatherIndex);
}
return indexList;
}
public List<Index> buildVertexOlapIndex(BaseVertex vertex) {
List<Index> indexs = new ArrayList<>();
Id pkId = vertex.getProperties().keySet().iterator().next();
Collection<IndexLabel> indexLabels = graph.indexLabels();
for (IndexLabel il : indexLabels) {
if (il.indexFields().contains(pkId)) {
indexs.addAll(this.buildIndex(vertex, il));
}
}
return indexs;
}
public List<Index> buildVertexIndex(BaseVertex vertex) {
List<Index> indexs = new ArrayList<>();
VertexLabel label = vertex.schemaLabel();
if (label.enableLabelIndex()) {
indexs.addAll(this.buildLabelIndex(vertex));
}
for (Id il : label.indexLabels()) {
indexs.addAll(this.buildIndex(vertex, graph.indexLabel(il)));
}
return indexs;
}
public List<Index> buildEdgeIndex(BaseEdge edge) {
List<Index> indexs = new ArrayList<>();
EdgeLabel label = edge.schemaLabel();
if (label.enableLabelIndex()) {
indexs.addAll(this.buildLabelIndex(edge));
}
for (Id il : label.indexLabels()) {
indexs.addAll(this.buildIndex(edge, graph.indexLabel(il)));
}
return indexs;
}
/**
* Build index(user properties) of vertex or edge
* Notice: This method does not use unique index validation to check if the current element already exists
*
* @param indexLabel the index label
* @param element the properties owner
*/
public List<Index> buildIndex(BaseElement element, IndexLabel indexLabel) {
E.checkArgument(indexLabel != null,
"Not exist index label with id '%s'", indexLabel.id());
List<Index> indexs = new ArrayList<>();
// Collect property values of index fields
List<Object> allPropValues = new ArrayList<>();
int fieldsNum = indexLabel.indexFields().size();
int firstNullField = fieldsNum;
for (Id fieldId : indexLabel.indexFields()) {
BaseProperty<Object> property = element.getProperty(fieldId);
if (property == null) {
E.checkState(hasNullableProp(element, fieldId),
"Non-null property '%s' is null for '%s'",
graph.propertyKey(fieldId), element);
if (firstNullField == fieldsNum) {
firstNullField = allPropValues.size();
}
allPropValues.add(INDEX_SYM_NULL);
} else {
E.checkArgument(!INDEX_SYM_NULL.equals(property.value()),
"Illegal value of index property: '%s'",
INDEX_SYM_NULL);
allPropValues.add(property.value());
}
}
if (firstNullField == 0 && !indexLabel.indexType().isUnique()) {
// The property value of first index field is null
return indexs;
}
// Not build index for record with nullable field (except unique index)
List<Object> propValues = allPropValues.subList(0, firstNullField);
// Expired time
long expiredTime = element.expiredTime();
// Build index for each index type
switch (indexLabel.indexType()) {
case RANGE_INT:
case RANGE_FLOAT:
case RANGE_LONG:
case RANGE_DOUBLE:
E.checkState(propValues.size() == 1,
"Expect only one property in range index");
Object value = NumericUtil.convertToNumber(propValues.get(0));
indexs.add(this.buildIndex(indexLabel, value, element.id(),
expiredTime));
break;
case SEARCH:
E.checkState(propValues.size() == 1,
"Expect only one property in search index");
value = propValues.get(0);
Set<String> words =
this.segmentWords(propertyValueToString(value));
for (String word : words) {
indexs.add(this.buildIndex(indexLabel, word, element.id(),
expiredTime));
}
break;
case SECONDARY:
// Secondary index maybe include multi prefix index
if (isCollectionIndex(propValues)) {
/*
* Property value is a collection
* we should create index for each item
*/
for (Object propValue :
(Collection<Object>) propValues.get(0)) {
value = ConditionQuery.concatValuesLimitLength(
propValue);
value = escapeIndexValueIfNeeded((String) value);
indexs.add(this.buildIndex(indexLabel, value,
element.id(),
expiredTime));
}
} else {
for (int i = 0, n = propValues.size(); i < n; i++) {
List<Object> prefixValues =
propValues.subList(0, i + 1);
value = ConditionQuery.concatValuesLimitLength(
prefixValues);
value = escapeIndexValueIfNeeded((String) value);
indexs.add(this.buildIndex(indexLabel, value,
element.id(),
expiredTime));
}
}
break;
case SHARD:
value = ConditionQuery.concatValuesLimitLength(propValues);
value = escapeIndexValueIfNeeded((String) value);
indexs.add(this.buildIndex(indexLabel, value, element.id(),
expiredTime));
break;
case UNIQUE:
value = ConditionQuery.concatValuesLimitLength(allPropValues);
assert !"".equals(value);
indexs.add(this.buildIndex(indexLabel, value, element.id(),
expiredTime));
break;
default:
throw new AssertionError(String.format(
"Unknown index type '%s'", indexLabel.indexType()));
}
return indexs;
}
private Index buildIndex(IndexLabel indexLabel, Object propValue,
Id elementId, long expiredTime) {
Index index = new Index(graph, indexLabel, true);
index.fieldValues(propValue);
index.elementIds(elementId, expiredTime);
return index;
}
private static String escapeIndexValueIfNeeded(String value) {
for (int i = 0; i < value.length(); i++) {
char ch = value.charAt(i);
if (ch <= INDEX_SYM_MAX) {
/*
* Escape symbols can't be used due to impossible to parse,
* and treat it as illegal value for the origin text property
*/
E.checkArgument(false, "Illegal char '\\u000%s' " +
"in index property: '%s'", (int) ch,
value);
}
}
if (value.isEmpty()) {
// Escape empty String to INDEX_SYM_EMPTY (char `\u0002`)
value = INDEX_SYM_EMPTY;
}
return value;
}
private static boolean hasNullableProp(BaseElement element, Id key) {
return element.schemaLabel().nullableKeys().contains(key);
}
private static boolean isCollectionIndex(List<Object> propValues) {
return propValues.size() == 1 &&
propValues.get(0) instanceof Collection;
}
private Set<String> segmentWords(String text) {
return this.textAnalyzer.segment(text);
}
private static String propertyValueToString(Object value) {
/*
* Join collection items with white space if the value is Collection,
* or else keep the origin value.
*/
return value instanceof Collection ?
StringUtils.join(((Collection<Object>) value).toArray(), " ") :
value.toString();
}
}

View File

@ -0,0 +1,23 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.type;
public interface GraphType extends Namifiable, Typifiable {
}

View File

@ -0,0 +1,213 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.type;
import java.util.HashMap;
import java.util.Map;
import org.apache.hugegraph.type.define.SerialEnum;
public enum HugeType implements SerialEnum {
UNKNOWN(0, "UNKNOWN"),
/* Schema types */
VERTEX_LABEL(1, "VL"),
EDGE_LABEL(2, "EL"),
PROPERTY_KEY(3, "PK"),
INDEX_LABEL(4, "IL"),
COUNTER(50, "C"),
/* Data types */
VERTEX(101, "V"),
// System meta
SYS_PROPERTY(102, "S"),
// Property
PROPERTY(103, "U"),
// Vertex aggregate property
AGGR_PROPERTY_V(104, "VP"),
// Edge aggregate property
AGGR_PROPERTY_E(105, "EP"),
// Olap property
OLAP(106, "AP"),
// Edge
EDGE(120, "E"),
// Edge's direction is OUT for the specified vertex
EDGE_OUT(130, "O"),
// Edge's direction is IN for the specified vertex
EDGE_IN(140, "I"),
SECONDARY_INDEX(150, "SI"),
VERTEX_LABEL_INDEX(151, "VI"),
EDGE_LABEL_INDEX(152, "EI"),
RANGE_INT_INDEX(160, "II"),
RANGE_FLOAT_INDEX(161, "FI"),
RANGE_LONG_INDEX(162, "LI"),
RANGE_DOUBLE_INDEX(163, "DI"),
SEARCH_INDEX(170, "AI"),
SHARD_INDEX(175, "HI"),
UNIQUE_INDEX(178, "UI"),
TASK(180, "T"),
SERVER(181, "SERVER"),
VARIABLE(185,"VA"),
KV_TYPE(200, "KV"),
KV_RAW(201, "KVR"),
// System schema
SYS_SCHEMA(250, "SS"),
MAX_TYPE(255, "~");
private byte type = 0;
private String name;
private static final Map<String, HugeType> ALL_NAME = new HashMap<>();
static {
SerialEnum.register(HugeType.class);
for (HugeType type : values()) {
ALL_NAME.put(type.name, type);
}
}
HugeType(int type, String name) {
assert type < 256;
this.type = (byte) type;
this.name = name;
}
@Override
public byte code() {
return this.type;
}
public String string() {
return this.name;
}
public String readableName() {
return this.name().replace('_', ' ').toLowerCase();
}
public boolean isSchema() {
return this == HugeType.VERTEX_LABEL ||
this == HugeType.EDGE_LABEL ||
this == HugeType.PROPERTY_KEY ||
this == HugeType.INDEX_LABEL;
}
public boolean isGraph() {
return this.isVertex() || this.isEdge() ;
}
public boolean isVertex() {
// Consider task vertex variable as the same, all used to store HugeVertex structure
return this == HugeType.VERTEX || this == HugeType.TASK ||
this == HugeType.VARIABLE;
}
public boolean isEdge() {
return this == EDGE || this == EDGE_OUT || this == EDGE_IN;
}
public boolean isEdgeLabel() {
return this == EDGE_LABEL;
}
public boolean isIndex() {
return this == VERTEX_LABEL_INDEX || this == EDGE_LABEL_INDEX ||
this == SECONDARY_INDEX || this == SEARCH_INDEX ||
this == RANGE_INT_INDEX || this == RANGE_FLOAT_INDEX ||
this == RANGE_LONG_INDEX || this == RANGE_DOUBLE_INDEX ||
this == SHARD_INDEX || this == UNIQUE_INDEX;
}
public boolean isLabelIndex() {
return this == VERTEX_LABEL_INDEX || this == EDGE_LABEL_INDEX;
}
public boolean isStringIndex() {
return this == VERTEX_LABEL_INDEX || this == EDGE_LABEL_INDEX ||
this == SECONDARY_INDEX || this == SEARCH_INDEX ||
this == SHARD_INDEX || this == UNIQUE_INDEX;
}
public boolean isNumericIndex() {
return this == RANGE_INT_INDEX || this == RANGE_FLOAT_INDEX ||
this == RANGE_LONG_INDEX || this == RANGE_DOUBLE_INDEX ||
this == SHARD_INDEX;
}
public boolean isSecondaryIndex() {
return this == VERTEX_LABEL_INDEX || this == EDGE_LABEL_INDEX ||
this == SECONDARY_INDEX;
}
public boolean isSearchIndex() {
return this == SEARCH_INDEX;
}
public boolean isRangeIndex() {
return this == RANGE_INT_INDEX || this == RANGE_FLOAT_INDEX ||
this == RANGE_LONG_INDEX || this == RANGE_DOUBLE_INDEX;
}
public boolean isRange4Index() {
return this == RANGE_INT_INDEX || this == RANGE_FLOAT_INDEX;
}
public boolean isRange8Index() {
return this == RANGE_LONG_INDEX || this == RANGE_DOUBLE_INDEX;
}
public boolean isShardIndex() {
return this == SHARD_INDEX;
}
public boolean isUniqueIndex() {
return this == UNIQUE_INDEX;
}
public boolean isVertexAggregateProperty() {
return this == AGGR_PROPERTY_V;
}
public boolean isEdgeAggregateProperty() {
return this == AGGR_PROPERTY_E;
}
public boolean isAggregateProperty() {
return this.isVertexAggregateProperty() ||
this.isEdgeAggregateProperty();
}
public static HugeType fromString(String type) {
return ALL_NAME.get(type);
}
public static HugeType fromCode(byte code) {
return SerialEnum.fromCode(HugeType.class, code);
}
}

View File

@ -0,0 +1,27 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.type;
import org.apache.hugegraph.id.Id;
public interface Idfiable {
public Id id();
}

View File

@ -0,0 +1,29 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.type;
import org.apache.hugegraph.id.Id;
import java.util.Set;
public interface Indexfiable {
public Set<Id> indexLabels();
}

View File

@ -0,0 +1,31 @@
// Copyright 2017 JanusGraph Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package org.apache.hugegraph.type;
/**
* Represents an entity that can be uniquely identified by a String name.
*
* @author Matthias Broecheler (me@matthiasb.com)
*/
public interface Namifiable {
/**
* Returns the unique name of this entity.
*
* @return Name of this entity.
*/
String name();
}

View File

@ -0,0 +1,29 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.type;
import java.util.Set;
import org.apache.hugegraph.id.Id;
public interface Propfiable {
public Set<Id> properties();
}

View File

@ -0,0 +1,26 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.type;
public interface Typifiable {
// Return schema/data type
public HugeType type();
}

View File

@ -0,0 +1,76 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.type.define;
public enum Action implements SerialEnum {
INSERT(1, "insert"),
APPEND(2, "append"),
ELIMINATE(3, "eliminate"),
DELETE(4, "delete"),
UPDATE_IF_PRESENT(5, "update_if_present"),
UPDATE_IF_ABSENT(6, "update_if_absent");
private final byte code;
private final String name;
static {
SerialEnum.register(Action.class);
}
Action(int code, String name) {
assert code < 256;
this.code = (byte) code;
this.name = name;
}
@Override
public byte code() {
return this.code;
}
public String string() {
return this.name;
}
public static Action fromCode(byte code) {
switch (code) {
case 1:
return INSERT;
case 2:
return APPEND;
case 3:
return ELIMINATE;
case 4:
return DELETE;
case 5:
return UPDATE_IF_PRESENT;
case 6:
return UPDATE_IF_ABSENT;
default:
throw new AssertionError("Unsupported action code: " + code);
}
}
}

View File

@ -0,0 +1,93 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.type.define;
public enum AggregateType implements SerialEnum {
NONE(0, "none"),
MAX(1, "max"),
MIN(2, "min"),
SUM(3, "sum"),
OLD(4, "old"),
SET(5, "set"),
LIST(6, "list");
private final byte code;
private final String name;
static {
SerialEnum.register(AggregateType.class);
}
AggregateType(int code, String name) {
assert code < 256;
this.code = (byte) code;
this.name = name;
}
@Override
public byte code() {
return this.code;
}
public String string() {
return this.name;
}
public boolean isNone() {
return this == NONE;
}
public boolean isMax() {
return this == MAX;
}
public boolean isMin() {
return this == MIN;
}
public boolean isSum() {
return this == SUM;
}
public boolean isNumber() {
return this.isMax() || this.isMin() || this.isSum();
}
public boolean isOld() {
return this == OLD;
}
public boolean isSet() {
return this == SET;
}
public boolean isList() {
return this == LIST;
}
public boolean isUnion() {
return this == SET || this == LIST;
}
public boolean isIndexable() {
return this == NONE || this == MAX || this == MIN || this == OLD;
}
}

View File

@ -0,0 +1,69 @@
// Copyright 2017 JanusGraph Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package org.apache.hugegraph.type.define;
/**
* The cardinality of the values associated with given key for a particular element.
*
* @author Matthias Broecheler (me@matthiasb.com)
*/
public enum Cardinality implements SerialEnum {
/**
* Only a single value may be associated with the given key.
*/
SINGLE(1, "single"),
/**
* Multiple values and duplicate values may be associated with the given
* key.
*/
LIST(2, "list"),
/**
* Multiple but distinct values may be associated with the given key.
*/
SET(3, "set");
private byte code = 0;
private String name = null;
static {
SerialEnum.register(Cardinality.class);
}
Cardinality(int code, String name) {
assert code < 256;
this.code = (byte) code;
this.name = name;
}
@Override
public byte code() {
return this.code;
}
public String string() {
return this.name;
}
public boolean single() {
return this == SINGLE;
}
public boolean multiple() {
return this == LIST || this == SET;
}
}

View File

@ -0,0 +1,68 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.type.define;
public enum CollectionType implements SerialEnum {
// Java Collection Framework
JCF(1, "jcf"),
// Eclipse Collection
EC(2, "ec"),
// FastUtil
FU(3, "fu");
private final byte code;
private final String name;
static {
SerialEnum.register(CollectionType.class);
}
CollectionType(int code, String name) {
assert code < 256;
this.code = (byte) code;
this.name = name;
}
@Override
public byte code() {
return this.code;
}
public String string() {
return this.name;
}
public static CollectionType fromCode(byte code) {
switch (code) {
case 1:
return JCF;
case 2:
return EC;
case 3:
return FU;
default:
throw new AssertionError(
"Unsupported collection code: " + code);
}
}
}

View File

@ -0,0 +1,224 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.type.define;
import java.nio.ByteBuffer;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import org.apache.hugegraph.util.Bytes;
import org.apache.hugegraph.util.DateUtil;
import org.apache.hugegraph.exception.HugeException;
import org.apache.hugegraph.serializer.BytesBuffer;
import org.apache.hugegraph.util.Blob;
import org.apache.hugegraph.util.StringEncoding;
import com.google.common.collect.ImmutableSet;
public enum DataType implements SerialEnum {
UNKNOWN(0, "unknown", Object.class),
OBJECT(1, "object", Object.class),
BOOLEAN(2, "boolean", Boolean.class),
BYTE(3, "byte", Byte.class),
INT(4, "int", Integer.class),
LONG(5, "long", Long.class),
FLOAT(6, "float", Float.class),
DOUBLE(7, "double", Double.class),
TEXT(8, "text", String.class),
BLOB(9, "blob", Blob.class),
DATE(10, "date", Date.class),
UUID(11, "uuid", UUID.class);
private final byte code;
private final String name;
private final Class<?> clazz;
private static final ImmutableSet<String> SPECIAL_FLOATS = ImmutableSet.of("-Infinity", "Infinity", "NaN");
static {
SerialEnum.register(DataType.class);
}
DataType(int code, String name, Class<?> clazz) {
assert code < 256;
this.code = (byte) code;
this.name = name;
this.clazz = clazz;
}
@Override
public byte code() {
return this.code;
}
public String string() {
return this.name;
}
public Class<?> clazz() {
return this.clazz;
}
public boolean isText() {
return this == DataType.TEXT;
}
public boolean isNumber() {
return this == BYTE || this == INT || this == LONG ||
this == FLOAT || this == DOUBLE;
}
public boolean isNumber4() {
// Store index value of Byte using 4 bytes
return this == BYTE || this == INT || this == FLOAT;
}
public boolean isNumber8() {
return this == LONG || this == DOUBLE;
}
public boolean isBlob() {
return this == DataType.BLOB;
}
public boolean isDate() {
return this == DataType.DATE;
}
public boolean isUUID() {
return this == DataType.UUID;
}
public <V> Number valueToNumber(V value) {
if (!(this.isNumber() && value instanceof Number) &&
!(value instanceof String && SPECIAL_FLOATS.contains(value))) {
return null;
}
if (this.clazz.isInstance(value)) {
return (Number) value;
}
Number number;
try {
switch (this) {
case BYTE:
number = Byte.valueOf(value.toString());
break;
case INT:
number = Integer.valueOf(value.toString());
break;
case LONG:
number = Long.valueOf(value.toString());
break;
case FLOAT:
number = Float.valueOf(value.toString());
break;
case DOUBLE:
number = Double.valueOf(value.toString());
break;
default:
throw new AssertionError(String.format(
"Number type only contains Byte, Integer, " +
"Long, Float, Double, but got %s", this.clazz()));
}
} catch (NumberFormatException e) {
throw new IllegalArgumentException(String.format(
"Can't read '%s' as %s: %s",
value, this.name, e.getMessage()));
}
return number;
}
public <V> Date valueToDate(V value) {
if (!this.isDate()) {
return null;
}
if (value instanceof Date) {
return (Date) value;
} else if (value instanceof Integer) {
return new Date(((Number) value).intValue());
} else if (value instanceof Long) {
return new Date(((Number) value).longValue());
} else if (value instanceof String) {
return DateUtil.parse((String) value);
}
return null;
}
public <V> UUID valueToUUID(V value) {
if (!this.isUUID()) {
return null;
}
if (value instanceof UUID) {
return (UUID) value;
} else if (value instanceof String) {
return StringEncoding.uuid((String) value);
}
return null;
}
public <V> Blob valueToBlob(V value) {
if (!this.isBlob()) {
return null;
}
if (value instanceof Blob) {
return (Blob) value;
} else if (value instanceof byte[]) {
return Blob.wrap((byte[]) value);
} else if (value instanceof ByteBuffer) {
return Blob.wrap(((ByteBuffer) value).array());
} else if (value instanceof BytesBuffer) {
return Blob.wrap(((BytesBuffer) value).bytes());
} else if (value instanceof String) {
// Only base64 string or hex string accepted
String str = ((String) value);
if (str.startsWith("0x")) {
return Blob.wrap(Bytes.fromHex(str.substring(2)));
}
return Blob.wrap(StringEncoding.decodeBase64(str));
} else if (value instanceof List) {
List<?> values = (List<?>) value;
byte[] bytes = new byte[values.size()];
for (int i = 0; i < bytes.length; i++) {
Object v = values.get(i);
if (v instanceof Byte || v instanceof Integer) {
bytes[i] = ((Number) v).byteValue();
} else {
throw new IllegalArgumentException(String.format(
"expect byte or int value, but got '%s'", v));
}
}
return Blob.wrap(bytes);
}
return null;
}
public static DataType fromClass(Class<?> clazz) {
for (DataType type : DataType.values()) {
if (type.clazz() == clazz) {
return type;
}
}
throw new HugeException("Unknown clazz '%s' for DataType", clazz);
}
}

View File

@ -0,0 +1,89 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.type.define;
import org.apache.hugegraph.type.HugeType;
public enum Directions implements SerialEnum {
// TODO: add NONE enum for non-directional edges
BOTH(0, "both"),
OUT(1, "out"),
IN(2, "in");
private byte code = 0;
private String name = null;
static {
SerialEnum.register(Directions.class);
}
Directions(int code, String name) {
assert code < 256;
this.code = (byte) code;
this.name = name;
}
@Override
public byte code() {
return this.code;
}
public String string() {
return this.name;
}
public HugeType type() {
switch (this) {
case OUT:
return HugeType.EDGE_OUT;
case IN:
return HugeType.EDGE_IN;
default:
throw new IllegalArgumentException(String.format(
"Can't convert direction '%s' to HugeType", this));
}
}
public Directions opposite() {
if (this.equals(OUT)) {
return IN;
} else {
return this.equals(IN) ? OUT : BOTH;
}
}
public static Directions convert(HugeType edgeType) {
switch (edgeType) {
case EDGE_OUT:
return OUT;
case EDGE_IN:
return IN;
default:
throw new IllegalArgumentException(String.format(
"Can't convert type '%s' to Direction", edgeType));
}
}
}

View File

@ -0,0 +1,72 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.type.define;
public enum EdgeLabelType implements SerialEnum {
NORMAL(1, "NORMAL"),
PARENT(2, "PARENT"),
SUB(3, "SUB"),
GENERAL(4, "GENERAL"),
;
private final byte code;
private final String name;
static {
SerialEnum.register(EdgeLabelType.class);
}
EdgeLabelType(int code, String name) {
assert code < 256;
this.code = (byte) code;
this.name = name;
}
@Override
public byte code() {
return this.code;
}
public String string() {
return this.name;
}
public boolean normal() {
return this == NORMAL;
}
public boolean parent() {
return this == PARENT;
}
public boolean sub() {
return this == SUB;
}
public boolean general() {
return this == GENERAL;
}
}

View File

@ -0,0 +1,51 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.type.define;
public enum Frequency implements SerialEnum {
DEFAULT(0, "default"),
SINGLE(1, "single"),
MULTIPLE(2, "multiple");
private byte code = 0;
private String name = null;
static {
SerialEnum.register(Frequency.class);
}
Frequency(int code, String name) {
assert code < 256;
this.code = (byte) code;
this.name = name;
}
@Override
public byte code() {
return this.code;
}
public String string() {
return this.name;
}
}

View File

@ -0,0 +1,108 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.type.define;
public enum HugeKeys {
UNKNOWN(0, "undefined"),
/* Column names of schema type (common) */
ID(1, "id"),
NAME(2, "name"),
TIMESTAMP(3, "timestamp"),
SCHEMA_TYPE(4, "schema_type"),
USER_DATA(10, "user_data"),
STATUS(11, "status"),
/* Column names of schema type (VertexLabel) */
ID_STRATEGY(50, "id_strategy"),
PROPERTIES(51, "properties"),
PRIMARY_KEYS(52, "primary_keys"),
INDEX_LABELS(53, "index_labels"),
NULLABLE_KEYS(54, "nullable_keys"),
ENABLE_LABEL_INDEX(55, "enable_label_index"),
/* Column names of schema type (EdgeLabel) */
LINKS(80, "links"),
FREQUENCY(81, "frequency"),
SOURCE_LABEL(82, "source_label"),
TARGET_LABEL(83, "target_label"),
SORT_KEYS(84, "sort_keys"),
TTL(85, "ttl"),
TTL_START_TIME(86, "ttl_start_time"),
EDGELABEL_TYPE(87, "edgelabel_type"),
PARENT_LABEL(89, "parent_label"),
/* Column names of schema type (PropertyKey) */
DATA_TYPE(120, "data_type"),
CARDINALITY(121, "cardinality"),
AGGREGATE_TYPE(122, "aggregate_type"),
WRITE_TYPE(123, "write_type"),
/* Column names of schema type (IndexLabel) */
BASE_TYPE(150, "base_type"),
BASE_VALUE(151, "base_value"),
INDEX_TYPE(152, "index_type"),
FIELDS(153, "fields"),
/* Column names of index data */
INDEX_NAME(180, "index_name"),
FIELD_VALUES(181, "field_values"),
INDEX_LABEL_ID(182, "index_label_id"),
ELEMENT_IDS(183, "element_ids"),
/* Column names of data type (Vertex/Edge) */
LABEL(200, "label"),
OWNER_VERTEX(201, "owner_vertex"),
OTHER_VERTEX(202, "other_vertex"),
PROPERTY_KEY(203, "property_key"),
PROPERTY_VALUE(204, "property_value"),
DIRECTION(205, "direction"),
SORT_VALUES(206, "sort_values"),
PRIMARY_VALUES(207, "primary_values"),
EXPIRED_TIME(208, "expired_time"),
SUB_LABEL(211,"sub_label"),
PROPERTY_TYPE(249, "property_type"),
AGGREGATE_PROPERTIES(250, "aggregate_properties"),
;
public static final long NORMAL_PROPERTY_ID = 0L;
/* HugeKeys define */
private byte code = 0;
private String name = null;
HugeKeys(int code, String name) {
assert code < 256;
this.code = (byte) code;
this.name = name;
}
public byte code() {
return this.code;
}
public String string() {
return this.name;
}
}

View File

@ -0,0 +1,71 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.type.define;
public enum IdStrategy implements SerialEnum {
DEFAULT(0, "default"),
AUTOMATIC(1, "automatic"),
PRIMARY_KEY(2, "primary_key"),
CUSTOMIZE_STRING(3, "customize_string"),
CUSTOMIZE_NUMBER(4, "customize_number"),
CUSTOMIZE_UUID(5, "customize_uuid");
private byte code = 0;
private String name = null;
static {
SerialEnum.register(IdStrategy.class);
}
IdStrategy(int code, String name) {
assert code < 256;
this.code = (byte) code;
this.name = name;
}
@Override
public byte code() {
return this.code;
}
public String string() {
return this.name;
}
public boolean isAutomatic() {
return this == AUTOMATIC;
}
public boolean isPrimaryKey() {
return this == PRIMARY_KEY;
}
public boolean isCustomized() {
return this == CUSTOMIZE_STRING ||
this == CUSTOMIZE_NUMBER ||
this == CUSTOMIZE_UUID;
}
}

View File

@ -0,0 +1,122 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.type.define;
import org.apache.hugegraph.type.HugeType;
public enum IndexType implements SerialEnum {
// For secondary query
SECONDARY(1, "secondary"),
// For range query
RANGE(2, "range"),
RANGE_INT(21, "range_int"),
RANGE_FLOAT(22, "range_float"),
RANGE_LONG(23, "range_long"),
RANGE_DOUBLE(24, "range_double"),
// For full-text query (not supported now)
SEARCH(3, "search"),
// For prefix + range query
SHARD(4, "shard"),
// For unique index
UNIQUE(5, "unique");
private byte code = 0;
private String name = null;
static {
SerialEnum.register(IndexType.class);
}
IndexType(int code, String name) {
assert code < 256;
this.code = (byte) code;
this.name = name;
}
@Override
public byte code() {
return this.code;
}
public String string() {
return this.name;
}
public HugeType type() {
switch (this) {
case SECONDARY:
return HugeType.SECONDARY_INDEX;
case RANGE_INT:
return HugeType.RANGE_INT_INDEX;
case RANGE_FLOAT:
return HugeType.RANGE_FLOAT_INDEX;
case RANGE_LONG:
return HugeType.RANGE_LONG_INDEX;
case RANGE_DOUBLE:
return HugeType.RANGE_DOUBLE_INDEX;
case SEARCH:
return HugeType.SEARCH_INDEX;
case SHARD:
return HugeType.SHARD_INDEX;
case UNIQUE:
return HugeType.UNIQUE_INDEX;
default:
throw new AssertionError(String.format(
"Unknown index type '%s'", this));
}
}
public boolean isString() {
return this == SECONDARY || this == SEARCH ||
this == SHARD || this == UNIQUE;
}
public boolean isNumeric() {
return this == RANGE_INT || this == RANGE_FLOAT ||
this == RANGE_LONG || this == RANGE_DOUBLE ||
this == SHARD;
}
public boolean isSecondary() {
return this == SECONDARY;
}
public boolean isRange() {
return this == RANGE_INT || this == RANGE_FLOAT ||
this == RANGE_LONG || this == RANGE_DOUBLE;
}
public boolean isSearch() {
return this == SEARCH;
}
public boolean isShard() {
return this == SHARD;
}
public boolean isUnique() {
return this == UNIQUE;
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.type.define;
public enum SchemaStatus implements SerialEnum {
CREATED(1, "created"),
CREATING(2, "creating"),
REBUILDING(3, "rebuilding"),
DELETING(4, "deleting"),
UNDELETED(5, "undeleted"),
INVALID(6, "invalid"),
CLEARING(7, "clearing");
private byte code = 0;
private String name = null;
static {
SerialEnum.register(SchemaStatus.class);
}
SchemaStatus(int code, String name) {
assert code < 256;
this.code = (byte) code;
this.name = name;
}
public boolean ok() {
return this == CREATED;
}
public boolean deleting() {
return this == DELETING || this == UNDELETED;
}
@Override
public byte code() {
return this.code;
}
public String string() {
return this.name;
}
}

View File

@ -0,0 +1,83 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.type.define;
import org.apache.hugegraph.exception.HugeException;
import org.apache.hugegraph.type.HugeType;
import org.apache.hugegraph.util.CollectionUtil;
import org.apache.hugegraph.util.E;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public interface SerialEnum {
public byte code();
// static Table<Class<?>, Byte, SerialEnum> table = HashBasedTable.create();
static Map<Class, Map<Byte,SerialEnum>>table =new ConcurrentHashMap<>();
public static void register(Class<? extends SerialEnum> clazz) {
Object enums;
try {
enums = clazz.getMethod("values").invoke(null);
} catch (Exception e) {
throw new HugeException("Exception in backend", e);
}
ConcurrentHashMap map=new ConcurrentHashMap<Byte,SerialEnum>();
for (SerialEnum e : CollectionUtil.<SerialEnum>toList(enums)) {
map.put(e.code(), e);
}
table.put(clazz,map);
}
public static <T extends SerialEnum> T fromCode(Class<T> clazz, byte code) {
Map clazzMap=table.get(clazz);
if (clazzMap == null) {
SerialEnum.register(clazz);
clazzMap=table.get(clazz);
}
E.checkArgument(clazzMap != null, "Can't get class registery for %s",
clazz.getSimpleName());
T value = (T) clazzMap.get(code);
if (value == null) {
E.checkArgument(false, "Can't construct %s from code %s",
clazz.getSimpleName(), code);
}
return value;
}
public static void registerInternalEnums() {
SerialEnum.register(Action.class);
SerialEnum.register(AggregateType.class);
SerialEnum.register(Cardinality.class);
SerialEnum.register(DataType.class);
SerialEnum.register(Directions.class);
SerialEnum.register(Frequency.class);
SerialEnum.register(HugeType.class);
SerialEnum.register(IdStrategy.class);
SerialEnum.register(IndexType.class);
SerialEnum.register(SchemaStatus.class);
// SerialEnum.register(HugePermission.class);
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.type.define;
public enum WriteType implements SerialEnum {
// OLTP property key
OLTP(1, "oltp"),
// OLAP property key without index
OLAP_COMMON(2, "olap_common"),
// OLAP property key with secondary index
OLAP_SECONDARY(3, "olap_secondary"),
// OLAP property key with range index
OLAP_RANGE(4, "olap_range");
private final byte code;
private final String name;
static {
SerialEnum.register(WriteType.class);
}
WriteType(int code, String name) {
assert code < 256;
this.code = (byte) code;
this.name = name;
}
@Override
public byte code() {
return this.code;
}
public String string() {
return this.name;
}
public boolean oltp() {
return this == OLTP;
}
public boolean olap() {
return this == OLAP_COMMON ||
this == OLAP_RANGE ||
this == OLAP_SECONDARY;
}
}

View File

@ -0,0 +1,73 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.util;
import java.util.Arrays;
import org.apache.hugegraph.util.Bytes;
import org.apache.hugegraph.util.E;
public class Blob implements Comparable<Blob> {
public static final Blob EMPTY = new Blob(new byte[0]);
private final byte[] bytes;
private Blob(byte[] bytes) {
E.checkNotNull(bytes, "bytes");
this.bytes = bytes;
}
public byte[] bytes() {
return this.bytes;
}
public static Blob wrap(byte[] bytes) {
return new Blob(bytes);
}
@Override
public int hashCode() {
return Arrays.hashCode(this.bytes);
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Blob)) {
return false;
}
Blob other = (Blob) obj;
return Arrays.equals(this.bytes, other.bytes);
}
@Override
public String toString() {
String hex = Bytes.toHex(this.bytes);
StringBuilder sb = new StringBuilder(6 + hex.length());
sb.append("Blob{").append(hex).append("}");
return sb.toString();
}
@Override
public int compareTo(Blob other) {
E.checkNotNull(other, "other blob");
return Bytes.compare(this.bytes, other.bytes);
}
}

View File

@ -0,0 +1,34 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.util;
public class GraphUtils {
private static final String HIDDEN_PREFIX = "~";
/**
* Determine if it is a system variable
* @param key
* @return
*/
public static boolean isHidden(final String key) {
return key.startsWith(HIDDEN_PREFIX);
}
}

View File

@ -0,0 +1,95 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.util;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import org.apache.hugegraph.exception.BackendException;
import org.apache.hugegraph.serializer.BytesBuffer;
import net.jpountz.lz4.LZ4BlockInputStream;
import net.jpountz.lz4.LZ4BlockOutputStream;
import net.jpountz.lz4.LZ4Compressor;
import net.jpountz.lz4.LZ4Factory;
import net.jpountz.lz4.LZ4FastDecompressor;
public class LZ4Util {
protected static final float DEFAULT_BUFFER_RATIO = 1.5f;
public static BytesBuffer compress(byte[] bytes, int blockSize) {
return compress(bytes, blockSize, DEFAULT_BUFFER_RATIO);
}
public static BytesBuffer compress(byte[] bytes, int blockSize,
float bufferRatio) {
float ratio = bufferRatio <= 0.0F ? DEFAULT_BUFFER_RATIO : bufferRatio;
LZ4Factory factory = LZ4Factory.fastestInstance();
LZ4Compressor compressor = factory.fastCompressor();
int initBufferSize = Math.round(bytes.length / ratio);
BytesBuffer buf = new BytesBuffer(initBufferSize);
LZ4BlockOutputStream lz4Output = new LZ4BlockOutputStream(
buf, blockSize, compressor);
try {
lz4Output.write(bytes);
lz4Output.close();
} catch (IOException e) {
throw new BackendException("Failed to compress", e);
}
/*
* If need to perform reading outside the method,
* remember to call forReadWritten()
*/
return buf;
}
public static BytesBuffer decompress(byte[] bytes, int blockSize) {
return decompress(bytes, blockSize, DEFAULT_BUFFER_RATIO);
}
public static BytesBuffer decompress(byte[] bytes, int blockSize,
float bufferRatio) {
float ratio = bufferRatio <= 0.0F ? DEFAULT_BUFFER_RATIO : bufferRatio;
LZ4Factory factory = LZ4Factory.fastestInstance();
LZ4FastDecompressor decompressor = factory.fastDecompressor();
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
int initBufferSize = Math.min(Math.round(bytes.length * ratio),
BytesBuffer.MAX_BUFFER_CAPACITY);
BytesBuffer buf = new BytesBuffer(initBufferSize);
LZ4BlockInputStream lzInput = new LZ4BlockInputStream(bais,
decompressor);
int count;
byte[] buffer = new byte[blockSize];
try {
while ((count = lzInput.read(buffer)) != -1) {
buf.write(buffer, 0, count);
}
lzInput.close();
} catch (IOException e) {
throw new BackendException("Failed to decompress", e);
}
/*
* If need to perform reading outside the method,
* remember to call forReadWritten()
*/
return buf;
}
}

View File

@ -0,0 +1,203 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
// Copyright 2017 JanusGraph Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package org.apache.hugegraph.util;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.UUID;
import org.apache.hugegraph.util.Bytes;
import org.apache.hugegraph.util.E;
import org.mindrot.jbcrypt.BCrypt;
import org.apache.hugegraph.exception.HugeException;
import org.apache.hugegraph.serializer.BytesBuffer;
import com.google.common.base.CharMatcher;
/**
* @author Matthias Broecheler (me@matthiasb.com)
* @author HugeGraph Authors
*/
public final class StringEncoding {
private static final MessageDigest DIGEST;
private static final byte[] BYTES_EMPTY = new byte[0];
private static final int BLOCK_SIZE = 4096;
static {
final String ALG = "SHA-256";
try {
DIGEST = MessageDigest.getInstance(ALG);
} catch (NoSuchAlgorithmException e) {
throw new HugeException("Failed to load algorithm %s", e, ALG);
}
}
private static final Base64.Encoder BASE64_ENCODER = Base64.getEncoder();
private static final Base64.Decoder BASE64_DECODER = Base64.getDecoder();
// Similar to {@link StringSerializer}
public static int writeAsciiString(byte[] array, int offset, String value) {
E.checkArgument(CharMatcher.ascii().matchesAllOf(value),
"'%s' must be ASCII string", value);
int len = value.length();
if (len == 0) {
array[offset++] = (byte) 0x80;
return offset;
}
int i = 0;
do {
int c = value.charAt(i);
assert c <= 127;
byte b = (byte) c;
if (++i == len) {
b |= 0x80; // End marker
}
array[offset++] = b;
} while (i < len);
return offset;
}
public static String readAsciiString(byte[] array, int offset) {
StringBuilder sb = new StringBuilder();
int c = 0;
do {
c = 0xFF & array[offset++];
if (c != 0x80) {
sb.append((char) (c & 0x7F));
}
} while ((c & 0x80) <= 0);
return sb.toString();
}
public static int getAsciiByteLength(String value) {
E.checkArgument(CharMatcher.ascii().matchesAllOf(value),
"'%s' must be ASCII string", value);
return value.isEmpty() ? 1 : value.length();
}
public static byte[] encode(String value) {
try {
return value.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
throw new HugeException("Failed to encode string", e);
}
}
public static String decode(byte[] bytes) {
try {
return new String(bytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new HugeException("Failed to decode string", e);
}
}
public static String decode(byte[] bytes, int offset, int length) {
try {
return new String(bytes, offset, length, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new HugeException("Failed to decode string", e);
}
}
public static String encodeBase64(byte[] bytes) {
return BASE64_ENCODER.encodeToString(bytes);
}
public static byte[] decodeBase64(String value) {
if (value.isEmpty()) {
return BYTES_EMPTY;
}
return BASE64_DECODER.decode(value);
}
public static byte[] compress(String value) {
return compress(value, LZ4Util.DEFAULT_BUFFER_RATIO);
}
public static byte[] compress(String value, float bufferRatio) {
BytesBuffer buf = LZ4Util.compress(encode(value), BLOCK_SIZE,
bufferRatio);
return buf.bytes();
}
public static String decompress(byte[] value) {
return decompress(value, LZ4Util.DEFAULT_BUFFER_RATIO);
}
public static String decompress(byte[] value, float bufferRatio) {
BytesBuffer buf = LZ4Util.decompress(value, BLOCK_SIZE, bufferRatio);
return decode(buf.array(), 0, buf.position());
}
public static String hashPassword(String password) {
return BCrypt.hashpw(password, BCrypt.gensalt(4));
}
public static boolean checkPassword(String candidatePassword,
String dbPassword) {
return BCrypt.checkpw(candidatePassword, dbPassword);
}
public static String sha256(String string) {
byte[] stringBytes = encode(string);
DIGEST.reset();
return StringEncoding.encodeBase64(DIGEST.digest(stringBytes));
}
public static String format(byte[] bytes) {
return String.format("%s[0x%s]", decode(bytes), Bytes.toHex(bytes));
}
public static UUID uuid(String value) {
E.checkArgument(value != null, "The UUID can't be null");
try {
if (value.contains("-") && value.length() == 36) {
return UUID.fromString(value);
}
// UUID represented by hex string
E.checkArgument(value.length() == 32,
"Invalid UUID string: %s", value);
String high = value.substring(0, 16);
String low = value.substring(16);
return new UUID(Long.parseUnsignedLong(high, 16),
Long.parseUnsignedLong(low, 16));
} catch (NumberFormatException ignored) {
throw new IllegalArgumentException("Invalid UUID string: " + value);
}
}
}

View File

@ -0,0 +1,264 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.util.collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.hugegraph.util.E;
import org.eclipse.collections.api.map.primitive.IntObjectMap;
import org.eclipse.collections.api.map.primitive.MutableIntObjectMap;
import org.eclipse.collections.impl.list.mutable.FastList;
import org.eclipse.collections.impl.map.mutable.UnifiedMap;
import org.eclipse.collections.impl.map.mutable.primitive.IntObjectHashMap;
import org.eclipse.collections.impl.set.mutable.UnifiedSet;
import org.apache.hugegraph.id.Id;
import org.apache.hugegraph.type.define.CollectionType;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
public class CollectionFactory {
private final CollectionType type;
public CollectionFactory() {
this.type = CollectionType.EC;
}
public CollectionFactory(CollectionType type) {
this.type = type;
}
public <V> List<V> newList() {
return newList(this.type);
}
public <V> List<V> newList(int initialCapacity) {
return newList(this.type, initialCapacity);
}
public <V> List<V> newList(Collection<V> collection) {
return newList(this.type, collection);
}
public static <V> List<V> newList(CollectionType type) {
switch (type) {
case EC:
return new FastList<>();
case JCF:
return new ArrayList<>();
case FU:
return new ObjectArrayList<>();
default:
throw new AssertionError(
"Unsupported collection type: " + type);
}
}
public static <V> List<V> newList(CollectionType type,
int initialCapacity) {
switch (type) {
case EC:
return new FastList<>(initialCapacity);
case JCF:
return new ArrayList<>(initialCapacity);
case FU:
return new ObjectArrayList<>(initialCapacity);
default:
throw new AssertionError(
"Unsupported collection type: " + type);
}
}
public static <V> List<V> newList(CollectionType type,
Collection<V> collection) {
switch (type) {
case EC:
return new FastList<>(collection);
case JCF:
return new ArrayList<>(collection);
case FU:
return new ObjectArrayList<>(collection);
default:
throw new AssertionError(
"Unsupported collection type: " + type);
}
}
public <V> Set<V> newSet() {
return newSet(this.type);
}
public <V> Set<V> newSet(int initialCapacity) {
return newSet(this.type, initialCapacity);
}
public <V> Set<V> newSet(Collection<V> collection) {
return newSet(this.type, collection);
}
public static <V> Set<V> newSet(CollectionType type) {
switch (type) {
case EC:
return new UnifiedSet<>();
case JCF:
return new HashSet<>();
case FU:
return new ObjectOpenHashSet<>();
default:
throw new AssertionError(
"Unsupported collection type: " + type);
}
}
public static <V> Set<V> newSet(CollectionType type,
int initialCapacity) {
switch (type) {
case EC:
return new UnifiedSet<>(initialCapacity);
case JCF:
return new HashSet<>(initialCapacity);
case FU:
return new ObjectOpenHashSet<>(initialCapacity);
default:
throw new AssertionError(
"Unsupported collection type: " + type);
}
}
public static <V> Set<V> newSet(CollectionType type,
Collection<V> collection) {
switch (type) {
case EC:
return new UnifiedSet<>(collection);
case JCF:
return new HashSet<>(collection);
case FU:
return new ObjectOpenHashSet<>(collection);
default:
throw new AssertionError(
"Unsupported collection type: " + type);
}
}
public <K, V> Map<K, V> newMap() {
return newMap(this.type);
}
public <K, V> Map<K, V> newMap(int initialCapacity) {
return newMap(this.type, initialCapacity);
}
public <K, V> Map<K, V> newMap(Map<? extends K, ? extends V> map) {
return newMap(this.type, map);
}
public static <K, V> Map<K, V> newMap(CollectionType type) {
/*
* EC is faster 10%-20% than JCF, and it's more stable & less
* memory cost(size is bigger, EC is better).
*/
switch (type) {
case EC:
return new UnifiedMap<>();
case JCF:
return new HashMap<>();
case FU:
return new Object2ObjectOpenHashMap<>();
default:
throw new AssertionError(
"Unsupported collection type: " + type);
}
}
public static <K, V> Map<K, V> newMap(CollectionType type,
int initialCapacity) {
switch (type) {
case EC:
return new UnifiedMap<>(initialCapacity);
case JCF:
return new HashMap<>(initialCapacity);
case FU:
return new Object2ObjectOpenHashMap<>(initialCapacity);
default:
throw new AssertionError(
"Unsupported collection type: " + type);
}
}
public static <K, V> Map<K, V> newMap(CollectionType type,
Map<? extends K, ? extends V> map) {
switch (type) {
case EC:
return new UnifiedMap<>(map);
case JCF:
return new HashMap<>(map);
case FU:
return new Object2ObjectOpenHashMap<>(map);
default:
throw new AssertionError(
"Unsupported collection type: " + type);
}
}
public static <V> MutableIntObjectMap<V> newIntObjectMap() {
return new IntObjectHashMap<>();
}
public static <V> MutableIntObjectMap<V> newIntObjectMap(int initialCapacity) {
return new IntObjectHashMap<>(initialCapacity);
}
public static <V> MutableIntObjectMap<V> newIntObjectMap(
IntObjectMap<? extends V> map) {
return new IntObjectHashMap<>(map);
}
@SuppressWarnings("unchecked")
public static <V> MutableIntObjectMap<V> newIntObjectMap(
Object... objects) {
IntObjectHashMap<V> map = IntObjectHashMap.newMap();
E.checkArgument(objects.length % 2 == 0,
"Must provide even arguments for " +
"CollectionFactory.newIntObjectMap");
for (int i = 0; i < objects.length; i += 2) {
int key = objects[i] instanceof Id ?
(int) ((Id) objects[i]).asLong() : (int) objects[i];
map.put(key, (V) objects[i + 1]);
}
return map;
}
public IdSet newIdSet() {
return newIdSet(this.type);
}
public static IdSet newIdSet(CollectionType type) {
return new IdSet(type);
}
}

View File

@ -0,0 +1,120 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.apache.hugegraph.util.collection;
import org.apache.hugegraph.id.Id;
import org.apache.hugegraph.id.IdGenerator;
import org.apache.hugegraph.type.define.CollectionType;
import org.apache.hugegraph.iterator.ExtendableIterator;
import org.eclipse.collections.api.iterator.MutableLongIterator;
import org.eclipse.collections.impl.set.mutable.primitive.LongHashSet;
import java.util.AbstractSet;
import java.util.Iterator;
import java.util.Set;
public class IdSet extends AbstractSet<Id> {
private final LongHashSet numberIds;
private final Set<Id> nonNumberIds;
public IdSet(CollectionType type) {
this.numberIds = new LongHashSet();
this.nonNumberIds = CollectionFactory.newSet(type);
}
@Override
public int size() {
return this.numberIds.size() + this.nonNumberIds.size();
}
@Override
public boolean isEmpty() {
return this.numberIds.isEmpty() && this.nonNumberIds.isEmpty();
}
@Override
public boolean contains(Object object) {
if (!(object instanceof Id)) {
return false;
}
Id id = (Id) object;
if (id.type() == Id.IdType.LONG) {
return this.numberIds.contains(id.asLong());
} else {
return this.nonNumberIds.contains(id);
}
}
@Override
public Iterator<Id> iterator() {
return new ExtendableIterator<>(
this.nonNumberIds.iterator(),
new EcIdIterator(this.numberIds.longIterator()));
}
@Override
public boolean add(Id id) {
if (id.type() == Id.IdType.LONG) {
return this.numberIds.add(id.asLong());
} else {
return this.nonNumberIds.add(id);
}
}
public boolean remove(Id id) {
if (id.type() == Id.IdType.LONG) {
return this.numberIds.remove(id.asLong());
} else {
return this.nonNumberIds.remove(id);
}
}
@Override
public void clear() {
this.numberIds.clear();
this.nonNumberIds.clear();
}
private static class EcIdIterator implements Iterator<Id> {
private final MutableLongIterator iterator;
public EcIdIterator(MutableLongIterator iter) {
this.iterator = iter;
}
@Override
public boolean hasNext() {
return this.iterator.hasNext();
}
@Override
public Id next() {
return IdGenerator.of(this.iterator.next());
}
@Override
public void remove() {
this.iterator.remove();
}
}
}

25
pom.xml
View File

@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.hugegraph</groupId>
@ -104,6 +104,7 @@
<module>hugegraph-commons</module>
<module>install-dist</module>
<module>hugegraph-cluster-test</module>
<module>hugegraph-struct</module>
</modules>
<dependencyManagement>
@ -133,20 +134,28 @@
<!-- Accept the pom module -->
<acceptPomPackaging>true</acceptPomPackaging>
<!-- Using the template which is grouped by License file -->
<fileTemplate>/org/codehaus/mojo/license/third-party-file-groupByMultiLicense.ftl</fileTemplate>
<fileTemplate>/org/codehaus/mojo/license/third-party-file-groupByMultiLicense.ftl
</fileTemplate>
<licenseMerges>
<licenseMerge>The Apache Software License, Version 2.0|The Apache License, Version 2.0</licenseMerge>
<licenseMerge>The Apache Software License, Version 2.0|Apache License, Version 2.0</licenseMerge>
<licenseMerge>The Apache Software License, Version 2.0|Apache Public License 2.0</licenseMerge>
<licenseMerge>The Apache Software License, Version 2.0|The Apache License, Version
2.0
</licenseMerge>
<licenseMerge>The Apache Software License, Version 2.0|Apache License, Version 2.0
</licenseMerge>
<licenseMerge>The Apache Software License, Version 2.0|Apache Public License 2.0
</licenseMerge>
<licenseMerge>The Apache Software License, Version 2.0|Apache 2</licenseMerge>
<licenseMerge>The Apache Software License, Version 2.0|Apache 2.0</licenseMerge>
<licenseMerge>The Apache Software License, Version 2.0|Apache-2.0</licenseMerge>
<licenseMerge>The Apache Software License, Version 2.0|Apache License 2.0</licenseMerge>
<licenseMerge>The Apache Software License, Version 2.0|Apache License, version 2.0</licenseMerge>
<licenseMerge>The Apache Software License, Version 2.0|Apache License 2.0
</licenseMerge>
<licenseMerge>The Apache Software License, Version 2.0|Apache License, version 2.0
</licenseMerge>
<licenseMerge>3-Clause BSD License|BSD 3-clause</licenseMerge>
<licenseMerge>3-Clause BSD License|BSD 3-Clause</licenseMerge>
<licenseMerge>Eclipse Public License v1.0|Eclipse Public License 1.0</licenseMerge>
<licenseMerge>Eclipse Public License v1.0|Eclipse Public License - v 1.0</licenseMerge>
<licenseMerge>Eclipse Public License v1.0|Eclipse Public License - v 1.0
</licenseMerge>
<licenseMerge>The MIT License|MIT License</licenseMerge>
</licenseMerges>
</configuration>