Невозможно запросить локальную версию базы данных связанных фильмов
Я пытаюсь запросить локальную версию базы данных связанных фильмов с помощью SPARQL. Файл в формате N-Triples и его размер составляет примерно 450 МБ. Я использую сервлеты для реализации. Теперь, когда я передаю запрос, сервлету требуется более пяти минут для его обработки, и в конце я получаю следующее исключение:
type Exception report
message
description The server encountered an internal error () that prevented it from fulfilling this request.
exception
javax.servlet.ServletException: Servlet execution threw an exception
root cause
java.lang.OutOfMemoryError: Java heap space
java.util.Arrays.copyOfRange(Arrays.java:3209)
java.lang.String.<init>(String.java:215)
java.lang.StringBuilder.toString(StringBuilder.java:430)
org.openjena.riot.tokens.TokenizerText.allBetween(TokenizerText.java:732)
org.openjena.riot.tokens.TokenizerText.parseToken(TokenizerText.java:152)
org.openjena.riot.tokens.TokenizerText.hasNext(TokenizerText.java:69)
org.openjena.atlas.iterator.PeekIterator.fill(PeekIterator.java:37)
org.openjena.atlas.iterator.PeekIterator.next(PeekIterator.java:77)
org.openjena.riot.lang.LangBase.nextToken(LangBase.java:145)
org.openjena.riot.lang.LangNTriples.parseOne(LangNTriples.java:59)
org.openjena.riot.lang.LangNTriples.parseOne(LangNTriples.java:21)
org.openjena.riot.lang.LangNTuple.runParser(LangNTuple.java:58)
org.openjena.riot.lang.LangBase.parse(LangBase.java:75)
org.openjena.riot.system.JenaReaderNTriples2.readWorker(JenaReaderNTriples2.java:28)
org.openjena.riot.system.JenaReaderRIOT.readImpl(JenaReaderRIOT.java:124)
org.openjena.riot.system.JenaReaderRIOT.read(JenaReaderRIOT.java:79)
com.hp.hpl.jena.rdf.model.impl.ModelCom.read(ModelCom.java:226)
com.hp.hpl.jena.util.FileManager.readModelWorker(FileManager.java:395)
com.hp.hpl.jena.util.FileManager.loadModelWorker(FileManager.java:299)
com.hp.hpl.jena.util.FileManager.loadModel(FileManager.java:250)
ServletExample.runQuery(ServletExample.java:92)
ServletExample.doGet(ServletExample.java:62)
javax.servlet.http.HttpServlet.service(HttpServlet.java:627)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
note The full stack trace of the root cause is available in the Apache Tomcat/5.5.31 logs.
Мой код:
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import com.hp.hpl.jena.query.*;
import com.hp.hpl.jena.rdf.model.*;
import com.hp.hpl.jena.util.FileManager;
public class ServletExample
extends HttpServlet
{
/***********************************/
/* Constants */
/***********************************/
private static final long serialVersionUID = 1L;
public static final String SPARQL_ENDPOINT = "http://data.linkedmdb.org/sparql";
public static final String QUERY ="PREFIX m: <http://data.linkedmdb.org/resource/movie/>"
+"SELECT DISTINCT ?actorName WHERE {"+
"?dir1 m:director_name \"Sofia Coppola\"."+
"?dir2 m:director_name \"Francis Ford Coppola\"."+
"?dir1film m:director ?dir1;"+
"m:actor ?actor."+
"?dir2film m:director ?dir2;"+
"m:actor ?actor."+
"?actor m:actor_name ?actorName."+
"}";
/*"PREFIX m: <http://data.linkedmdb.org/resource/movie/>\n" +
"SELECT DISTINCT ?actorName WHERE {\n" +
" ?dir1 m:director_name %dir_name_1%.\n" +
" ?dir2 m:director_name %dir_name_2%.\n" +
" ?dir1film m:director ?dir1;\n" +
" m:actor ?actor.\n" +
" ?dir2film m:director ?dir2;\n" +
" m:actor ?actor.\n" +
" ?actor m:actor_name ?actorName.\n" +
"}\n" +
"";*/
private static final String HEADER = "<html>\n" +
" <head>\n" +
" <title>results</title>\n" +
" <link href=\"simple.css\" type=\"text/css\" rel=\"stylesheet\" />\n" +
" </head>\n" +
" <body>\n" +
"";
private static final String FOOTER = "</body></html>";
/**
* Respond to HTTP GET request. Will need to be mounted against some URL
* pattern in web.xml
*/
@Override
protected void doGet( HttpServletRequest req, HttpServletResponse resp )
throws ServletException, IOException
{
String dir1 = req.getParameter( "dir1" );//"Sofia";
String dir2 = req.getParameter( "dir2" );//"Francis Ford Coppola";
//String dir1 = "Sofia";
//String dir2 = "Francis Ford Coppola";
if (dir1 == null || dir2 == null || dir1.isEmpty() || dir2.isEmpty()) {
noInput( resp );
}
else {
runQuery( resp, dir1, dir2 );
}
}
protected void noInput( HttpServletResponse resp )
throws IOException
{
header( resp );
resp.getWriter().println( "<p>Please select director names as query params <code>dir1</code> and <code>dir2</code></p>" );
footer( resp );
}
protected void footer( HttpServletResponse resp ) throws IOException {
resp.getWriter().println( FOOTER );
}
protected void header( HttpServletResponse resp ) throws IOException {
resp.getWriter().println( HEADER );
}
protected void runQuery( HttpServletResponse resp, String dir1, String dir2 )
throws IOException
{
PrintWriter out = resp.getWriter();
// Set up the query
// String q = QUERY.replace( "%dir_name_1%", "\"" + dir1 + "\"" )
// .replace( "%dir_name_2%", "\"" + dir2 + "\"" );
String q=QUERY;
Query query = QueryFactory.create( q ) ;
Model model = FileManager.get().loadModel( "e:\\applications\\linkedmdb-18-05-2009-dump\\dump.nt" );
// QueryExecution qexec = QueryExecutionFactory.sparqlService( SPARQL_ENDPOINT, query );
//com.hp.hpl.jena.query.Query query = QueryFactory.create(QUERY);
QueryExecution qexec = QueryExecutionFactory.create(query, model);
// perform the query
ResultSet results = qexec.execSelect();
// generate the output
header( resp );
if (!results.hasNext()) {
out.println( "<p>No results, sorry.</p>" );
}
else {
out.println( "<h1>Results</h1>" );
while (results.hasNext()) {
QuerySolution qs = results.next();
String actorName = qs.getLiteral( "actorName" ).getLexicalForm();
out.println( String.format( "<div>Actor named: %s</div>", actorName ) );
}
}
footer( resp );
}
}
Есть ли способ разрешить это исключение?
2 ответа
Кажется, вы загружаете все свои данные в память, используя Jena/RIOT. Насколько я знаю, LinkedIMDB достаточно велик, чтобы вызвать проблемы с этим подходом. То, что вы делаете, - это перенос всей вашей базы данных в память.
Увеличение кучи вашей JVM может быть одним из возможных решений, но оно не будет масштабироваться, если ваши данные будут расти.
Правильное решение - использовать другие конфигурации Jena, разработанные для таких размеров наборов данных. Это:
- Jena SDB, которая использует реляционные базы данных в качестве бэкэнда.
- Jena TDB, которая использует собственное хранилище Java на основе индексов B-деревьев для ускорения запросов. Масштабируется лучше, чем (1).
По желанию вы можете пойти на масштабируемые базы данных RDF, такие как 4store, и запросить данные через Jena ARQ. Это решение, безусловно, будет масштабироваться и работать лучше.
У вас заканчивается куча памяти в виртуальной машине Java (JVM). Либо увеличьте объем памяти кучи, доступной для JVM, либо разработайте для своего программного обеспечения использование меньшего объема памяти, например, обработайте содержимое небольшими порциями.
Чтобы увеличить память кучи, добавьте эти параметры в сценарий запуска вашего контейнера сервлетов или сервера приложений, где-то ваш java
исполняется двоичный файл Это говорит JVM, что он может использовать до 512 мегабайт памяти, если этого недостаточно, попробуйте с большими значениями:
-Xmx512m
Трудно сказать, как улучшить программное обеспечение, чтобы использовать меньше памяти, не видя реального кода.