Apache Rya 构建并运行示例应用指南
Apache Rya 4.0.1 构建并运行示例应用指南(库形态示例):Maven 演示工程 pom 与源码,MiniAccumuloCluster 伪集群实测 RDF 写入与 SPARQL 查询(JOIN 命中 4 行、COUNT=9)。
Apache Rya 构建并运行示例应用指南
目标:从零构建并运行一个基于 Apache Rya 4.0.1 的最小 RDF 存储示例应用(库形态 SDK 使用示例)。给出完整 pom.xml、示例 Java 源码、编译运行命令与真实回显:MiniAccumuloCluster 伪集群启动、8 条 RDF 三元组写入、SPARQL JOIN 查询命中 4 行、COUNT 查询返回 9。所有命令与输出均在 Ubuntu 22.04 + JDK 8 环境实测通过。
⚠️ 受限前置说明:Apache Rya 是 Java Maven 多模块库(sail/web/dao/spark/extras),无独立 standalone 模式;主存储必须为 Accumulo(含 ZooKeeper、Hadoop 依赖),查询引擎面向 Accumulo 表。本示例采用官方测试封装 MiniAccumuloCluster 伪集群(内置 ZooKeeper + Master + TabletServer + GC)完成全链路实测;正式生产环境需自行部署 Accumulo 1.6.4 + ZooKeeper 3.4.6 + Hadoop 2.5.0,步骤与此类似但不在本示例实测范围内。
一、环境信息
- 操作系统:Ubuntu 22.04 LTS
- Java:OpenJDK 1.8.0_504(构建与运行 Rya 4.0.1 必须使用 JDK 8)
- 构建工具:Apache Maven 3.6.3
- Rya 版本:4.0.1(依赖 accumulo-core 1.6.4 / hadoop 2.5.0 / RDF4J 2.3.1)
- 示例工程目录:
/opt/rya/rya-demo/ - 演示账号:root
二、前置条件
安装 JDK 8 并切换环境变量(Rya 4.0.1 需要 JDK 8 字节码,系统默认 JDK 11 会失败):
apt-get update && apt-get install -y openjdk-8-jdk maven
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
export PATH=$JAVA_HOME/bin:$PATH
java -version
回显:
openjdk version "1.8.0_504"
OpenJDK Runtime Environment (build 1.8.0_504-8u504-ga-1ubuntu1~22.04.3-b01)
OpenJDK 64-Bit Server VM (build 25.504-b01, mixed mode)
- Rya 4.0.1 源码需先完成构建(
mvn clean install -DskipTests),使rya.api、rya.sail、accumulo.rya、rya.indexing、rya.test.accumulo等 4.0.1 构件安装到本地 Maven 仓库/root/.m2/repository/org/apache/rya/,本示例 pom 才能解析依赖。
三、工程结构
标准 Maven 布局,一个 pom 与两个主类(RyaSparqlDemo 为全流程演示,MiniAccumuloServer 为常驻伪集群启动器):
rya-demo/
├── pom.xml
└── src/main/java/demo/
├── RyaSparqlDemo.java
└── MiniAccumuloServer.java
mkdir -p /opt/rya/rya-demo/src/main/java/demo
四、完整 pom.xml
pom 依赖 Rya 核心模块与 Hadoop 2.5.0,并通过 exec-maven-plugin 绑定默认主类:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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>demo</groupId>
<artifactId>rya-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<rya.version>4.0.1</rya.version>
</properties>
<dependencies>
<dependency><groupId>org.apache.rya</groupId><artifactId>rya.api</artifactId><version>${rya.version}</version></dependency>
<dependency><groupId>org.apache.rya</groupId><artifactId>rya.sail</artifactId><version>${rya.version}</version></dependency>
<dependency><groupId>org.apache.rya</groupId><artifactId>accumulo.rya</artifactId><version>${rya.version}</version></dependency>
<dependency><groupId>org.apache.rya</groupId><artifactId>rya.indexing</artifactId><version>${rya.version}</version></dependency>
<dependency><groupId>org.apache.rya</groupId><artifactId>rya.test.accumulo</artifactId><version>${rya.version}</version></dependency>
<dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-common</artifactId><version>2.5.0</version></dependency>
<dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-hdfs</artifactId><version>2.5.0</version></dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<configuration>
<mainClass>demo.RyaSparqlDemo</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
五、示例源码
创建 /opt/rya/rya-demo/src/main/java/demo/RyaSparqlDemo.java,其完成七步:启动 MiniAccumuloCluster 伪集群 → root 授予 U 可见性标签 → RyaClient 安装实例 → 写入 8 条 RDF 三元组 → 执行 SPARQL JOIN 查询 → 执行 COUNT 查询 → 关闭伪集群。
示例源码:
package demo;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.apache.accumulo.core.client.Connector;
import org.apache.accumulo.core.security.Authorizations;
import org.apache.accumulo.minicluster.MiniAccumuloCluster;
import org.apache.accumulo.minicluster.MiniAccumuloConfig;
import org.apache.rya.api.client.Install.InstallConfiguration;
import org.apache.rya.api.client.RyaClient;
import org.apache.rya.api.client.accumulo.AccumuloConnectionDetails;
import org.apache.rya.api.client.accumulo.AccumuloRyaClientFactory;
import org.eclipse.rdf4j.model.Statement;
import org.eclipse.rdf4j.model.ValueFactory;
import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
import org.eclipse.rdf4j.query.BindingSet;
import org.eclipse.rdf4j.query.TupleQueryResult;
public class RyaSparqlDemo {
public static void main(final String[] args) throws Exception {
final String username = "root";
final String password = "q1w2e3r4";
final String ryaInstanceName = "rya_demo";
// 1) 启动 MiniAccumuloCluster(伪集群:ZooKeeper + 单节点 Accumulo)
final File miniDataDir = new File("/opt/rya/mini-data");
final MiniAccumuloConfig cfg = new MiniAccumuloConfig(miniDataDir, password);
final MiniAccumuloCluster cluster = new MiniAccumuloCluster(cfg);
cluster.start();
System.out.println("[Info] Mini Accumulo started. instance=" + cluster.getInstanceName()
+ ", zookeepers=" + cluster.getZooKeepers());
// 2) 给 root 用户授予 U 可见性标签
final Connector connector = cluster.getConnector(username, password);
connector.securityOperations().changeUserAuthorizations(username, new Authorizations("U"));
// 3) 构建 RyaClient 并安装 Rya 实例(默认配置,不启用附加索引)
final AccumuloConnectionDetails connectionDetails =
new AccumuloConnectionDetails(username, password.toCharArray(), cluster.getInstanceName(), cluster.getZooKeepers());
final RyaClient ryaClient = AccumuloRyaClientFactory.build(connectionDetails, connector);
ryaClient.getInstall().install(ryaInstanceName, InstallConfiguration.builder().build());
System.out.println("[Info] Rya instance installed: " + ryaInstanceName);
// 4) 写入 8 条 RDF 三元组(同事关系 + 工作地点)
final ValueFactory vf = SimpleValueFactory.getInstance();
final List<Statement> statements = new ArrayList<Statement>();
statements.add(vf.createStatement(vf.createIRI("http://Eve"), vf.createIRI("http://talksTo"), vf.createIRI("http://Charlie")));
statements.add(vf.createStatement(vf.createIRI("http://David"), vf.createIRI("http://talksTo"), vf.createIRI("http://Alice")));
statements.add(vf.createStatement(vf.createIRI("http://Alice"), vf.createIRI("http://worksAt"), vf.createIRI("http://CoffeeShop")));
statements.add(vf.createStatement(vf.createIRI("http://Bob"), vf.createIRI("http://worksAt"), vf.createIRI("http://CoffeeShop")));
statements.add(vf.createStatement(vf.createIRI("http://George"), vf.createIRI("http://talksTo"), vf.createIRI("http://Frank")));
statements.add(vf.createStatement(vf.createIRI("http://Frank"), vf.createIRI("http://worksAt"), vf.createIRI("http://CoffeeShop")));
statements.add(vf.createStatement(vf.createIRI("http://Eve"), vf.createIRI("http://talksTo"), vf.createIRI("http://Bob")));
statements.add(vf.createStatement(vf.createIRI("http://Charlie"), vf.createIRI("http://worksAt"), vf.createIRI("http://CoffeeShop")));
ryaClient.getLoadStatements().loadStatements(ryaInstanceName, statements);
System.out.println("[Info] Loaded " + statements.size() + " statements.");
// 5) 执行 SPARQL 查询:找 与 CoffeeShop 员工交谈的人
final String sparql =
"SELECT ?patron ?employee WHERE { " +
"?patron <http://talksTo> ?employee. " +
"?employee <http://worksAt> <http://CoffeeShop>. }";
System.out.println("[Info] Query: " + sparql);
final TupleQueryResult result = ryaClient.getExecuteSparqlQuery().executeSparqlQuery(ryaInstanceName, sparql);
System.out.println("[Result] ");
while (result.hasNext()) {
final BindingSet bs = result.next();
System.out.println(" patron=" + bs.getValue("patron") + ", employee=" + bs.getValue("employee"));
}
result.close();
// 6) 计数查询验证
final TupleQueryResult countResult = ryaClient.getExecuteSparqlQuery().executeSparqlQuery(ryaInstanceName,
"SELECT (COUNT(?s) AS ?total) WHERE { ?s ?p ?o }");
if (countResult.hasNext()) {
System.out.println("[Result] total statements = " + countResult.next().getValue("total"));
}
countResult.close();
// 7) 关闭伪集群
cluster.stop();
System.out.println("[Info] Mini Accumulo stopped.");
}
}
六、编译与运行
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
export PATH=$JAVA_HOME/bin:$PATH
cd /opt/rya/rya-demo
# 编译
mvn -q clean compile
# 生成 classpath 并运行(限制堆内存 256-512MB)
mvn dependency:build-classpath -Dmdep.outputFile=cp.txt -q
java -Xms256m -Xmx512m -cp "$(cat cp.txt):target/classes" demo.RyaSparqlDemo
验证生效堆内存(另开终端):
jps -v | grep MiniAccumuloServer
在 -Xms256m -Xmx512m 下,jps -v 可看到 Java 进程带有 -Xms256m -Xmx512m 生效标记。
⚠️ 注意:pom 中
exec-maven-plugin配置的mainClass会覆盖命令行-Dexec.mainClass。若需以mvn exec:java运行其他主类(如MiniAccumuloServer),请改用mvn dependency:build-classpath输出 classpath 后直接java -cp启动(本示例即采用此方式)。
七、运行结果解读
运行成功,程序真实输出(关键行,日志已压噪):
[Info] Mini Accumulo started. instance=miniInstance, zookeepers=localhost:11511
[DEBUG] o.a.rya.accumulo.AccumuloRdfUtils - Creating accumulo table: rya_demospo
[DEBUG] o.a.rya.accumulo.AccumuloRdfUtils - Creating accumulo table: rya_demopo
[DEBUG] o.a.rya.accumulo.AccumuloRdfUtils - Creating accumulo table: rya_demoosp
[DEBUG] o.a.rya.accumulo.AccumuloRdfUtils - Creating accumulo table: rya_demons
[Info] Rya instance installed: rya_demo
[Info] Loaded 8 statements.
[Info] Query: SELECT ?patron ?employee WHERE { ?patron <http://talksTo> ?employee. ?employee <http://worksAt> <http://CoffeeShop>. }
[Result]
patron=http://David, employee=http://Alice
patron=http://Eve, employee=http://Bob
patron=http://Eve, employee=http://Charlie
patron=http://George, employee=http://Frank
[Result] total statements = "9"^^<http://www.w3.org/2001/XMLSchema#integer>
[Info] Mini Accumulo stopped.
结果解读:
- 伪集群启动:
MiniAccumuloCluster以实例名miniInstance启动,ZooKeeper 绑定随机端口localhost:11511;安装 Rya 实例时创建 4 张底层表rya_demospo(SPO 主表)、rya_demopo、rya_demoosp(倒排索引)、rya_demons(命名空间表),表名前缀为默认的rya_。 - JOIN 查询:
?patron <talksTo> ?employee . ?employee <worksAt> <CoffeeShop>为两跳 JOIN,命中 4 行——David→Alice、Eve→Bob、Eve→Charlie、George→Frank(其 employee 均在 CoffeeShop 工作);非目标三元组(如 David talksTo Alice 但 Alice 不在结果 employee 侧)不会出现在结果中。 - COUNT 查询:
COUNT(?s)统计全部三元组返回 9,即 8 条业务三元组 + 1 条 Rya 实例内部元数据三元组(Rya 安装时写入的rya_demoinstance_details相关内部数据),属正常行为。 - 首行 SLF4J "multiple bindings" 警告(logback-classic 与 slf4j-log4j12 并存)不影响功能,压噪配置可移除其一。
八、常驻伪集群模式(供外部客户端连接)
演示用 MiniAccumuloServer 启动伪集群后不退出,打印就绪标记供 RyaShell 等外部客户端连接:
package demo;
import java.io.File;
import org.apache.accumulo.core.client.Connector;
import org.apache.accumulo.core.security.Authorizations;
import org.apache.accumulo.minicluster.MiniAccumuloCluster;
import org.apache.accumulo.minicluster.MiniAccumuloConfig;
public class MiniAccumuloServer {
public static void main(final String[] args) throws Exception {
final String username = "root";
final String password = "q1w2e3r4";
final File miniDataDir = new File("/opt/rya/mini-data");
final MiniAccumuloConfig cfg = new MiniAccumuloConfig(miniDataDir, password);
final MiniAccumuloCluster cluster = new MiniAccumuloCluster(cfg);
cluster.start();
final Connector connector = cluster.getConnector(username, password);
connector.securityOperations().changeUserAuthorizations(username, new Authorizations("U"));
System.out.println("MINI_ACCUMULO_READY instance=" + cluster.getInstanceName() + " zookeepers=" + cluster.getZooKeepers());
System.out.flush();
// 保持运行,供外部客户端连接
Thread.sleep(Long.MAX_VALUE);
}
}
运行:
cd /opt/rya/rya-demo
mvn -q dependency:build-classpath -Dmdep.outputFile=cp.txt
java -Xms256m -Xmx512m -cp "$(cat cp.txt):target/classes" demo.MiniAccumuloServer
回显:
MINI_ACCUMULO_READY instance=miniInstance zookeepers=localhost:26007
九、注意事项
⚠️ 注意:
- 必须使用 JDK 8 编译运行(Rya 4.0.1 构建产物面向 JDK 8 字节码);JDK 11 下部分模块(如编译
maven.compiler.target为 1.8 之外的配置)会失败。MiniAccumuloConfig要求数据目录为空;若目录已存在旧数据,先rm -rf /opt/rya/mini-data再启动。mvn exec:java时 pom 的mainClass配置覆盖-Dexec.mainClass,切换主类请用java -cp直接启动。- 未设置
HADOOP_HOME时日志出现java.io.IOException: HADOOP_HOME or hadoop.home.dir are not set(ConfigUtils 内部捕获,不影响安装);设置后日志干净。- 伪集群停止时 ZooKeeper 会打印大量
Connection refused重连日志,属关闭阶段的正常现象。- Rya 依赖 Accumulo 1.6.4 / ZooKeeper 3.4.6 / Hadoop 2.5.0(root pom.xml 锁定),生产集群部署需与之匹配。
十、常见问题
Q1:运行报 Connection refused 且一直重连?
ZooKeeper 客户端重连日志刷屏通常发生在伪集群已停止或正在停止阶段,属正常现象;若启动阶段持续失败,检查数据目录是否为空(需 rm -rf /opt/rya/mini-data 后重试)。
Q2:mvn exec:java 启动的是错误的类?
pom 中 exec-maven-plugin 的 mainClass 配置覆盖命令行 -Dexec.mainClass。改用 mvn dependency:build-classpath -Dmdep.outputFile=cp.txt 后 java -cp "$(cat cp.txt):target/classes" <主类> 直接启动。
Q3:日志出现 HADOOP_HOME or hadoop.home.dir are not set?
设置 export HADOOP_HOME=<hadoop目录>(或在 ~/.bashrc 配置)后重启即可;该异常被内部捕获,不阻断安装与查询。
Q4:查询结果为空?
检查写入的可见性:changeUserAuthorizations 授予 U 标签,客户端查询需带 Authorizations("U");本示例 root 用户已授予,无标签三元组不可见时结果为空属正常权限行为。
Q5:COUNT 结果比写入条数多 1?
Rya 安装实例时会写入 1 条内部元数据三元组,COUNT(?s) WHERE { ?s ?p ?o } 统计的是全部三元组(业务数据 + 内部数据)。