Pyqgis. медленная работа с выборкой

Вопросы по свободной ГИС QGIS. Сообщения об ошибках, предложения по улучшению, локализация.
Ответить
Аватара пользователя
Филиппов Владислав
Гуру
Сообщения: 1035
Зарегистрирован: 17 фев 2006, 06:28
Репутация: 144
Ваше звание: Геннадич
Откуда: Новосибирск
Контактная информация:

Pyqgis. медленная работа с выборкой

Сообщение Филиппов Владислав » 15 окт 2014, 08:53

Здравствуйте! Опять я с своими нубскими вопросами...
Что же я делаю не так?
Есть 2 слоя в КУГИС 2.4: первый из шейп-файла и содержит 11 объектов, второй из PostGIS и содержит 60 тысяч объектов.
Я пробегаю циклом по объектам первого слоя и пытаюсь найти объект(-ы) на втором. Всё работает, объекты находятся и возвращаются в виде featureIterator.
Так вот, если я не обращаюсь к полученному итератору, то весь код отрабатывается очень быстро, а если я хочу получить объект из итератора, то время работы серьёзно увеличивается.
В первом случае доли секунды, в втором 1 минута с копейками!!!

Код: Выделить всё

query  0:00:00.005000
query  0:00:00.005000
query  0:00:00.004000
query  0:00:00.005000
query  0:00:00.004000
query  0:00:00.004000
query  0:00:00.003000
query  0:00:00.004000
query  0:00:00.005000
query  0:00:00.003000
query  0:00:00.003000
Time 0:00:00.121000

query  0:00:00.044000
query  0:00:00.002000
query  0:00:00.004000
query  0:00:00.001000
query  0:00:00.001000
query  0:00:00.002000
query  0:00:00.002000
query  0:00:00.001000
query  0:00:00.002000
query  0:00:00.001000
query  0:00:00.002000
Time 0:01:17.934000
ну и сам скрипт

Код: Выделить всё

from datetime import datetime
import sys

newdata = iface.mapCanvas().layer(0)
existdata = iface.mapCanvas().layer(1)
objs = newdata.getFeatures()
idxNew = newdata.fieldNameIndex('Cadnumber')
idxEx = existdata.fieldNameIndex('Cadnumber')
new_data_count = 0
update_data_count = 0
insert_data_count = 0
start = datetime.now()
for NewObj in objs:
    startq = datetime.now()
    features = existdata.getFeatures(QgsFeatureRequest().setFilterExpression (u"\"Cadnumber\"= '" + NewObj.attributes()[idxNew] + "'"))
    print "query  " + str((datetime.now() -startq))
    for f in features:
        pass#вот тут засада!

end = datetime.now()
print "Time " + str(end - start)

Аватара пользователя
Дмитрий Барышников
Гуру
Сообщения: 2572
Зарегистрирован: 17 ноя 2009, 19:17
Репутация: 261
Откуда: Москва

Re: Pyqgis. медленная работа с выборкой

Сообщение Дмитрий Барышников » 15 окт 2014, 10:47

Возможно дело не в итераторе. Стоит попробовать просто считать из existdata столько же фич. Если время будет близко к считыванию из итератора, то такое поведение нормально.

Аватара пользователя
dab
Гуру
Сообщения: 671
Зарегистрирован: 16 дек 2011, 20:02
Репутация: 170
Ваше звание: Гуру
Откуда: Москва
Контактная информация:

Re: Pyqgis. медленная работа с выборкой

Сообщение dab » 15 окт 2014, 11:30

В таблице PostgreSQL есть индекс по полю Cadnumber?
len(features) какое значение?

Аватара пользователя
Филиппов Владислав
Гуру
Сообщения: 1035
Зарегистрирован: 17 фев 2006, 06:28
Репутация: 144
Ваше звание: Геннадич
Откуда: Новосибирск
Контактная информация:

Re: Pyqgis. медленная работа с выборкой

Сообщение Филиппов Владислав » 15 окт 2014, 11:34

Камрад, приветствую!
1. индекс (b-tree) есть
2. len у итератора как-то не получается получить, а вот len(list(features)) возвращает 1 (и это верно)

Аватара пользователя
dab
Гуру
Сообщения: 671
Зарегистрирован: 16 дек 2011, 20:02
Репутация: 170
Ваше звание: Гуру
Откуда: Москва
Контактная информация:

Re: Pyqgis. медленная работа с выборкой

Сообщение dab » 15 окт 2014, 11:48

Не знаю механизм выполнения getFeatures для слоя.
Быть может проще сделать так:
1. пройтись по объектам первого слоя и получить идентификаторы объектов;
2. для второго слоя применить subsetString и в параметре перечислить необходимые идентификаторы.
https://github.com/Biryuchkov/openLand/ ... on.py#L519

Аватара пользователя
Филиппов Владислав
Гуру
Сообщения: 1035
Зарегистрирован: 17 фев 2006, 06:28
Репутация: 144
Ваше звание: Геннадич
Откуда: Новосибирск
Контактная информация:

Re: Pyqgis. медленная работа с выборкой

Сообщение Филиппов Владислав » 15 окт 2014, 11:56

надо подумать...
задача собственно: из первого слоя (обновление из кадастровой) загрузить всё во второй слой (весь кадастр), проверяя на наличие объекта на втором слое. Если он есть н автором слое, удалять.

Аватара пользователя
dab
Гуру
Сообщения: 671
Зарегистрирован: 16 дек 2011, 20:02
Репутация: 170
Ваше звание: Гуру
Откуда: Москва
Контактная информация:

Re: Pyqgis. медленная работа с выборкой

Сообщение dab » 15 окт 2014, 14:00

Филиппов Владислав писал(а):... проверяя на наличие объекта на втором слое...
Я только про это.
Метод subsetString фактически трансформируется на клиенте в SQL запрос, который реализуется на стороне сервера.

Аватара пользователя
Филиппов Владислав
Гуру
Сообщения: 1035
Зарегистрирован: 17 фев 2006, 06:28
Репутация: 144
Ваше звание: Геннадич
Откуда: Новосибирск
Контактная информация:

Re: Pyqgis. медленная работа с выборкой

Сообщение Филиппов Владислав » 16 окт 2014, 08:37

получился вот такой брутфорс:

Код: Выделить всё

from datetime import datetime
import sys

newdata = iface.mapCanvas().layer(0)
existdata = iface.mapCanvas().layer(1)
objs = newdata.getFeatures()
idxNew = newdata.fieldNameIndex('Cadnumber')
idxEx = existdata.fieldNameIndex('Cadnumber')
fields = existdata.pendingFields()
new_data_count = 0
insert_data_count = 0
start = datetime.now()
listNewFeatures = []
search = "\"cadnumber\" IN ("
for NewObj in objs:
    search += "'" + NewObj.attributes()[idxNew] + "',"
    
    createFeature = QgsFeature()
    createFeature.setFields(fields, True)
    createFeature.setGeometry(NewObj.geometry())
    for index, atr in enumerate(NewObj.attributes()):
        createFeature.setAttribute(index+1, atr)
    listNewFeatures.append(createFeature)
    
search = search[:len(search) - 1] + ")"
print "query prepare " + str(datetime.now() - start)
startq = datetime.now()
delids = []
if existdata.setSubsetString(search):
    print "query " + str((datetime.now() -startq))
    print "finded objects = " + str(existdata.dataProvider().featureCount())
delids = list(existdata.allFeatureIds())
caps = existdata.dataProvider().capabilities()
if caps & QgsVectorDataProvider.AddFeatures:
    existdata.startEditing()
    try:
        existdata.dataProvider().deleteFeatures(delids)
        print "data deleted"
        existdata.addFeatures(listNewFeatures)
    except:
        existdata.rollBack(True)
        e = sys.exc_info()[0]
        print "error in data editing " + str(e)
    existdata.commitChanges()
    print "editing is complete"
else:
    print "editing is prohibited!"
end = datetime.now()
existdata.setSubsetString("")
print "All Time " + str(end - start)
работает 32 сек на 12 тыс объектов :) уже хорошо. Осталось теперь сделать обновление существующих объектов

Ответить

Вернуться в «QGIS»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость