Jena API使用详解(关注将本体持久化到MySQL后的操作及解决中文乱码等问题)
2013-11-15 13:12
906 查看
关于Jena的简介在很多博客中都能看到,例如对Jena的简单理解和一个例子,使用Jena将本体存入MySQL,Jena进阶等。在入门的时候,看这些文章总是很疑惑,对于存入数据库后的操作一无所知。因此,在做项目之余,把使用到的一些方法记录下来,以供将来查阅。
每张表存放的内容可以简单了解一下。主要关注的表是jena_g1t1_stmt,其存放了本体的数据,本体以三元组的形式存放在此表中。其中陈述表是指下表中的前两个表。
此时,完成了将本体的持久化,接下来想要对本体进行一些操作该怎么办?
执行了将本体从数据库读出的操作,可以打印出本体中的所有类,直观看到本体的类。获得了OntModel,可以进行其他很多的操作,如读取本体中所有的类、属性及实例,读取本体类与类的关系,给本体增加实例等等。
诸如此类的代码片段还有很多,在实际使用的时候,详细的内容可以查阅Jena的API文档,找到所需要的方法。不过在使用Jena API的时候,需要考虑效率问题。
接下来说两个遇到的问题。
注意OWL文件的编码和在从文件读取时设置”UTF8“。
还有最重要的一点是在写数据库的URL时应该写成:
设置成OWL_MEM_MICRO_RULE_INF可以获取到一个类的所有属性,但在获取类的时候除了我们定义的类,还会得到系统的一些类。这个问题暂时不知道如何解决。
在Jena的使用方面,我还是一个新手,刚接触了一段时间,很多问题的理解还很不全面,如有错漏,请指出。
将本体持久化到数据库
首先,还是不能免俗,说说如何将本体持久化到数据库的方法。总体的操作流程是将本体从owl文件中读出,建立一个数据库的连接,将Model存入数据库。这个过程的操作比较简单,见如下代码。其中需要注意的一点是:在这里的url设置是不正确的,这样设置的结果将导致中文乱码,正确的设置方法参见本文最后提到的问题解决方案。private final static String driver = "com.mysql.jdbc.Driver"; private final static String url = "jdbc:mysql://localhost/dbname"; private final static String db = "MySQL"; private final static String user = "your user name"; private final static String pwd = "your password"; /** * @param args */ public static void main(String[] args) { try { IDBConnection con = getConnection(url, user, pwd, db); Class.forName(driver); String path = "your owl file path"; createModel(con, "model name", path); con.close(); } catch (SQLException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } /** * get db connection * * @param dbUrl * @param dbUser * @param dbPwd * @param dbName * @return */ public static DBConnection getConnection(String dbUrl, String dbUser, String dbPwd, String dbName) { return new DBConnection(dbUrl, dbUser, dbPwd, dbName); } /** * read owl file, create the ontModel, and store in db * * @param conn * @param name * @param filePath * @return */ public static OntModel createModel(IDBConnection conn, String name, String filePath) { ModelMaker maker = ModelFactory.createModelRDBMaker(conn); Model model = maker.createModel(name); try { File file = new File(filePath); FileInputStream fis = new FileInputStream(file); InputStreamReader isr = new InputStreamReader(fis, "UTF-8"); model.read(isr, null); isr.close(); fis.close(); model.commit(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } OntModelSpec spec = new OntModelSpec(OntModelSpec.OWL_MEM); return ModelFactory.createOntologyModel(spec, model); }执行了上面的代码,会发现在MySQL数据库中可以看见生成的七张表。
每张表存放的内容可以简单了解一下。主要关注的表是jena_g1t1_stmt,其存放了本体的数据,本体以三元组的形式存放在此表中。其中陈述表是指下表中的前两个表。
表名 | 存储 |
jena_g1t1_stmt | 本体数据 |
jena_g1t0_reif | 经过处理的本体数据 |
jena_sys_stmt | 系统元数据 |
jena_graph | 每一个用户图的名字和唯一标志符 |
jena_long_lit | 陈述表中不便于直接存储的长字符常量 |
jena_long_uri | 陈述表中不便于直接存储的长URI |
jena_prefix | URI的前缀 |
将本体从数据库中读取成OntModel
对本体进一步的操作,需要完成的第一步工作是将本体以OntModel的形式从数据库中读出来。这一步的操作见下述代码。private final static String driver = "com.mysql.jdbc.Driver"; private final static String url = "jdbc:mysql://localhost/dbname"; private final static String db = "MySQL"; private final static String user = "your user name"; private final static String pwd = "your password"; /** * @param args */ public static void main(String[] args) { try { IDBConnection con = getConnection(url, user, pwd, db); Class.forName(driver); OntModel model = getModelFromDB(con,"test"); printModel(model); con.close(); } catch (SQLException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } /** * get db connection * * @param dbUrl * @param dbUser * @param dbPwd * @param dbName * @return */ public static DBConnection getConnection(String dbUrl, String dbUser, String dbPwd, String dbName) { return new DBConnection(dbUrl, dbUser, dbPwd, dbName); } /** * get OntModel from db * * @param con * @param name * @return */ public static OntModel getModelFromDB(IDBConnection con, String name) { ModelMaker maker = ModelFactory.createModelRDBMaker(con); Model model = maker.getModel(name); OntModel newmodel = ModelFactory.createOntologyModel( getModelSpec(maker), model); return newmodel; } /** * get model spec * * @param maker * @return */ public static OntModelSpec getModelSpec(ModelMaker maker) { OntModelSpec spec = new OntModelSpec(OntModelSpec.OWL_MEM); spec.setImportModelMaker(maker); return spec; } /** * print model * * @param model */ public static void printModel(OntModel model) { for (Iterator<OntClass> i = model.listClasses(); i.hasNext();) { OntClass oc = i.next(); System.out.println(oc.getLocalName()); } }进行此步操作时,会遇到一个推理机的设置问题。这个问题稍后进行一个详细的解释。
执行了将本体从数据库读出的操作,可以打印出本体中的所有类,直观看到本体的类。获得了OntModel,可以进行其他很多的操作,如读取本体中所有的类、属性及实例,读取本体类与类的关系,给本体增加实例等等。
读取本体的所有类及类的属性
使用listDeclaredProperty方法打印出的类的属性,这样打印属性在一般情况下是没有问题的。但是如果一个属性的定义域是一个集合(Collection)的时候,不管是打印集合中的哪个类都找不到该属性。当时看了这篇博文,以为成功了,但是在获取Model的时候设置推理机为OWL_MEM_MICRO_RULE_INF,虽然可以找到属于集合的属性,但是同时会找到一些我们所不需要的属性,如自带的某些属性OntProperty等等。/** * get all classes and properties * * @param model */ public static void getClasses(OntModel model) { for (ExtendedIterator<OntClass> ei = model.listClasses(); ei.hasNext();) { OntClass oc = ei.next(); System.out.println(oc.getLocalName()); for (ExtendedIterator<OntProperty> eip = oc .listDeclaredProperties(); eip.hasNext();) { OntProperty op = eip.next(); System.out.println(op.getLocalName()); } } }
读取一个类的所有实例
读取实例,可以用OntClass的listInstances()方法和OntModel的listIndividuals()方法。前者获取的是一个类的所有实例,后者获取的是整个本体中的实例。/** * get a individual * * @param model * @param prefix */ public static void getIndivProperties(OntModel model, String prefix) { OntClass w = model.getOntClass(prefix + "Writing"); for (ExtendedIterator<?> i = w.listInstances(); i.hasNext();) { Individual individual = (Individual) i.next(); System.out.println(individual.getLocalName()); for (StmtIterator si = individual.listProperties(); si.hasNext();) { StatementImpl sti = (StatementImpl) si.next(); System.out.println(sti.getSubject().getLocalName() + "--" + sti.getPredicate().getLocalName() + "--" + sti.getObject()); } } }
获取两个类的关系
获取两个类的关系时,使用了sparql语言查询。Jena API本身不提供直接的方法以获取两个类的关系。在使用MAC的时候遇到了一个问题,然而在Linux下不出现该情况。此问题为:在使用sparql语言查询时,会自动打开一个java的进程,在执行完操作后会自动关闭该进程。但我使用了Java的Play框架,就会出现这个java进程始终运行的情况,原因未知,具体情况和截图可以看这里。/** * Get relation (ObjectPropery) between two classes * * @param classname1 * @param classname2 * @return relationValue */ public static String getRelation(OntModel model, String classname1, String classname2) { // Get prefixes String defaultPrefix = model.getNsPrefixURI(""); String rdfsPrefix = model.getNsPrefixURI("rdfs"); String owlPrefix = model.getNsPrefixURI("owl"); // Create a new query String queryString = "PREFIX default: <" + defaultPrefix + ">\n" + "PREFIX rdfs: <" + rdfsPrefix + ">\n" + "PREFIX owl: <" + owlPrefix + ">\n" + "SELECT ?relation\n" + "WHERE { ?relation rdfs:domain default:" + classname1 + ".?relation rdfs:range default:" + classname2 + "}"; // Create the query Query query = QueryFactory.create(queryString); // Execute the query and obtain results QueryExecution qe = QueryExecutionFactory.create(query, model); ResultSet results = qe.execSelect(); // Get property value String relationValue; if (results.hasNext()) { QuerySolution result = results.nextSolution(); relationValue = result.get("relation").toString() .substring(defaultPrefix.length()); } else { relationValue = null; } // Important - free up resources used running the query qe.close(); return relationValue; }
创建一个实例
/** * create a individual * * @param model * @param prefix */ public static void createIndiv(OntModel model, String prefix) { OntClass oc = model.getOntClass("classname"); Individual individual = oc.createIndividual("individualname"); OntProperty op = model.getOntProperty(prefix + "propertyname"); individual.addProperty(op, "propertyvalue"); }
诸如此类的代码片段还有很多,在实际使用的时候,详细的内容可以查阅Jena的API文档,找到所需要的方法。不过在使用Jena API的时候,需要考虑效率问题。
OntClass oc = model.getOntClass("classname");这行代码的效率出奇的差,如果能有其他方法根据类名获取一个类的方法,希望告知。
接下来说两个遇到的问题。
中文乱码问题
一是在使用Jena API将本体持久化到数据库时出现的中文乱码的问题。注意OWL文件的编码和在从文件读取时设置”UTF8“。
还有最重要的一点是在写数据库的URL时应该写成:
jdbc:mysql://localhost/dbname?useUnicode=true&characterEncoding=utf8
推理机设置问题
二是在查询类的属性时,需要使用Jena的推理机,否则使用listDeclaredProperties方法直接打印只能找到一个类的独有属性,而无法找到属于多个类的公有属性。/** * get model spec * * @param maker * @return */ public static OntModelSpec getModelSpec(ModelMaker maker) { OntModelSpec spec = new OntModelSpec( OntModelSpec.OWL_MEM_MICRO_RULE_INF); spec.setImportModelMaker(maker); return spec; }但是这样做还是会遇到新的问题,可参见这里。
设置成OWL_MEM_MICRO_RULE_INF可以获取到一个类的所有属性,但在获取类的时候除了我们定义的类,还会得到系统的一些类。这个问题暂时不知道如何解决。
在Jena的使用方面,我还是一个新手,刚接触了一段时间,很多问题的理解还很不全面,如有错漏,请指出。
相关文章推荐
- 使用POI的HWPF操作word(未解决中文乱码问题)
- 解决rails与mysql结合使用时的中文乱码问题
- 使用MySQL保存中文数据时,经常会遇到乱码问题的解决思路
- 解决MySQL在使用命令时中文字符出现乱码的问题
- jsp servlet mysql fckeditor等配合使用时出现中文乱码的解决问题!
- Dos命令下操作MySql解决中文乱码问题
- 在Ubuntu/Linux环境下使用MySQL:解决在Linux环境下MySQL中文乱码的问题
- mysql导入导出数据中文乱码解决方法小结(1、navicat导入问题已解决,创建连接后修改连接属性,选择高级->将使用Mysql字符集复选框去掉,下拉框选择GBK->导入sql文件OK;2、phpmyadmin显示乱码的问题也解决,两步:1.将sql文件以utf8的字符集编码另存,2.将文件中sql语句中的字段字符集编码改成utf8,导入OK)
- Ubuntu15.10使用mysql 5.6.28中文乱码问题解决
- linux系统下mysql快速安装使用、远程访问及中文乱码问题解决
- Django中使用MySQL添加中文乱码的问题解决
- JSP,mysql,tomcat下(基于struts2)中文及其乱码问题的解决 5大配置点 使用UTF-8编码
- jsp和servlet操作mysql中文乱码问题的解决办法
- 解决使用cmd或powershell进行数据库(MySQL,SQLite3...)查询时中文乱码的问题
- mysql使用source 命令后表内中文乱码问题的解决方法
- 关于在MySQL 、 VC、 JSP 中使用UTF-8解决中文生僻字乱码的问题
- 解决使用secureCRT操作数据库时出现中文乱码问题
- 树莓派 Learning 002 装机后的必要操作 11 解决在使用SecureCRT软件链接树莓派时,SecureCRT软件的终端中显示树莓派的中文字体乱码的问题
- jsp和servlet操作mysql中文乱码问题的解决办法