Jena StmtIterator и база данных

Моя модель хранится в тройном хранилище (постоянство). Я хочу выбрать всех лиц, связанных с каким-либо именем документа.

Я могу сделать это двумя способами

1) SPARQL-запрос:

 PREFIX base:<http://example#>
  select ?s2 ?p2 ?o2 
    where {
      {?doc base:fullName <file:/c:/1.txt>; ?p1 ?o1
  } UNION { 
    ?s2 ?p2 ?o2 ;
    base:documentID ?doc    } 
  }

Вопрос: Как создать модель Jena из ResultSet?

2) StmtIterator stmtIterator = model.listStatements(...)

Проблема с этим подходом в том, что мне нужно использовать операцию model.listStatements(...) несколько раз:

а) получить URI документа по имени документа

б) получить список идентификаторов лиц, связанных с этим URI документа

в) наконец - получить коллекцию особей

Я беспокоюсь о производительности - 3 раза запускаю model.listStatements(...) - много запросов к базе данных.

Либо все данные считываются в память(сомневаюсь) из БД при создании модели:

     Dataset ds = RdfStoreFactory.connectDataset(store, conn);
     GraphStore graphStore = GraphStoreFactory.create(ds) ;

?


person GML-VS    schedule 26.07.2012    source источник


Ответы (1)


Вам нужно немного отступить и более четко подумать о том, что вы пытаетесь сделать. Ваш sparql-запрос, после того как он будет исправлен (см. ниже), отлично справится с созданием итератора по набору результатов, который предоставит вам свойства каждого из документов, которые вы ищете. В частности, вы получаете один набор привязок для каждого из s2, p2 и o2 для каждого значения в наборе результатов. Это то, что вы просите, когда указываете select ?s2 ?p2 ?o2. И обычно это то, что вы хотите: обычно мы выбираем некоторые значения из тройного хранилища, чтобы каким-то образом их обработать (например, отобразить их в списке в пользовательском интерфейсе), и для этого нам как раз нужен итератор по результатам. Вы можете сделать так, чтобы запрос возвращал вам модель, а не набор результатов, благодаря SPARQL построить запрос или SPARQL описать. Однако затем вам нужно перебрать ресурсы в модели, поэтому вы не намного продвинетесь вперед (за исключением того, что ваша модель меньше и находится в памяти).

Ваш запрос, кстати, можно улучшить. Переменные p1 и o1 заставляют механизм запросов выполнять бесполезную работу, поскольку вы никогда их не используете, и нет необходимости в объединении. Исправлено, ваш запрос должен быть:

PREFIX base:<http://example#>

select ?s2 ?p2 ?o2 
where {
  ?doc base:fullName <file:/c:/1.txt> .
  ?s2 base:documentID ?doc ;
      ?p2 ?o2 .
}

Для выполнения любого запроса, выбора, описания или построения из Java см. документацию Jena. .

Вы можете эффективно достичь тех же результатов, что и ваш запрос, используя API модели. Например, (не проверено):

Model m = ..... ; // your model here
String baseNS = "http://example#";
Resource fileName = m.createResource( "file:/c:/1.txt" );

// create RDF property objects for the properties we need. This can be done in
// a vocab class, or automated with schemagen
Property fullName = m.createProperty( baseNS + "fullName" );
Property documentID = m.createProperty( baseNS + "documentID" );

// find the ?doc with the given fullName
for (ResIterator i = m.listSubjectsWithProperty( fullName, fileName ); i.hasNext(); ) {
  Resource doc = i.next();

  // find all of the ?s2 whose documentID is ?doc
  for (StmtIterator j = m.listStatements( null, documentID, doc ); j.hasNext(); ) {
    Resource s2 = j.next().getSubject();

    // list the properties of ?s2
    for (StmtIterator k = s2.listProperties(); k.hasNext(); ) {
      Statement stmt = k.next();
      Property p2 = stmt.getPredicate();
      RDFNode o2 = stmt.getObject();

      // do something with s2 p2 o2 ...
    }
  }
}

Обратите внимание, что ваш дизайн схемы делает это более сложным, чем это необходимо. Если, например, ресурс полного имени документа имеет свойство base:isFullNameOf, то вы можете просто выполнить поиск, чтобы получить свойство doc. Точно так же непонятно, зачем нужно различать doc и s2: почему бы просто не привязать свойства документа к ресурсу doc?

Наконец: нет, открытие соединения с базой данных не загружает всю БД в память. Однако, в частности, TDB широко использует кэширование областей графа, чтобы сделать запросы более эффективными.

person Ian Dickinson    schedule 27.07.2012
comment
Понимаю. Спасибо за ваш ответ. Что, по вашему мнению, будет быстрее для большого постоянного триплстора: 1) выполнить SPARQL SELECT, получить ResultSet и создать из него модель или 2) несколько раз использовать listStatements()/listSubjectsWithProperty()? Или то же самое? Или трудно сказать? - person GML-VS; 27.07.2012
comment
У меня есть тройка для документа -‹DocURI, base:fullname, 'file:/c:/1.txt'› и другие тройки, связанные с этим документом - Individual -‹IndividualID, base:inDocument, DocURI› - person GML-VS; 27.07.2012
comment
Лично я бы пока не заморачивался насчет оптимизации. Создайте свое приложение, напишите множество модульных и функциональных тестов. Сделайте код максимально понятным и чистым. Если это окажется медленным, проведите спринт по оптимизации на основе данных профилирования, чтобы показать вам, где оптимизировать в первую очередь. - person Ian Dickinson; 27.07.2012
comment
Я понял вашу модель данных; Я предлагал возможные улучшения на основе показанного образца. Но в конечном итоге вы лучше всего понимаете проблему своего домена, поэтому вы будете лучшим человеком, чтобы судить, например, сколько уровней косвенности вам нужно. - person Ian Dickinson; 27.07.2012