GraphDB - очень медленный запрос sparql с двумя подключениями

В моей базе данных есть информация о документах, где каждый документ имеет категорию, например

PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX: <http://example.com>

:doc1 :hasCategory :category1 .
:category1 rdfs:label "Law" .

Таких утверждений около 100к.

Выполнение простого запроса для получения количества документов по категориям:

SELECT ?category (count(distinct ?doc) as ?count) WHERE {
    ?doc :hasCategory ?category .
} GROUP BY ?category

запуск занимает около 0,1 с.

Но чтобы вернуть и метки категорий:

SELECT ?category ?label (count(distinct ?doc) as ?count) WHERE {
            ?doc :hasCategory ?category .
            ?category rdfs:label ?label .
} GROUP BY ?category ?label

выполнение этого запроса занимает более 7 секунд.

Почему разница такая большая и есть ли более оптимизированный запрос, который я могу использовать для получения меток?


person user888734    schedule 14.06.2018    source источник
comment
Вы можете проверить и сравнить планы запросов обоих запросов. Вам действительно нужно группировать по ярлыкам в каждой категории? Если для каждой категории есть только один ярлык, попробуйте SELECT ?category (sample(?label) as ?l) (count(distinct ?doc) as ?count) WHERE { ...} GROUP BY ?category   -  person UninformedUser    schedule 14.06.2018
comment
Расчетное количество итераций для обоих запросов составляет 39926. sample уменьшил время, затрачиваемое на секунду, но все равно около 6 секунд   -  person user888734    schedule 14.06.2018
comment
Фактически это 39926 для первого запроса и 39926.4551683254 для второго запроса.   -  person user888734    schedule 14.06.2018
comment
Количество уникальных объектов для первого оператора ?doc :hasCategory ?category . всего 133. Я бы подумал, что нужно найти ярлыки только для 133 категорий.   -  person user888734    schedule 14.06.2018


Ответы (2)


Я обнаружил, что могу получить желаемый результат за 0,2 секунды с помощью следующего запроса:

SELECT ?category (sample(?lbl) as ?label) ?count WHERE {
    ?category rdfs:label ?lbl .
    {
        SELECT ?category (count(distinct ?doc) as ?count) WHERE {
            ?doc :hasCategory ?category .
        } GROUP BY ?category 
    }
} GROUP BY ?category ?count

Но я не очень понимаю, почему это эффективнее.

person user888734    schedule 14.06.2018

Версии GraphDB до выпуска 8.6 реализуют операцию GROUP BY с наивным LinkedHashMap, где хеш-ключ состоит из всех элементов, составляющих проекцию. Чтобы вычислить хэш-код, движок преобразует внутренний идентификатор в значение RDF. Если строки длиннее, они будут считаны из внешней коллекции, что приведет к дополнительной дисковой операции и дополнительному процессору для вычисления хэш-кода.

Единственный способ оптимизировать запрос - перейти на GraphDB 8.6 (в настоящее время это кандидат на поздний выпуск), который реализует более оптимизированный алгоритм агрегирования или уменьшает проекцию GROUP BY, как вы это сделали в своем ответе.

person vassil_momtchev    schedule 14.06.2018