Skip to content

Fixed/reworked VkTools.get_all_slow_iter method#121

Merged
python273 merged 14 commits intopython273:masterfrom
hdk5:get_all_slow_fix
Mar 23, 2018
Merged

Fixed/reworked VkTools.get_all_slow_iter method#121
python273 merged 14 commits intopython273:masterfrom
hdk5:get_all_slow_fix

Conversation

@hdk5
Copy link
Copy Markdown
Contributor

@hdk5 hdk5 commented Mar 19, 2018

Сначала я заметил, что в текущей реализации обрезаются первые max_count результатов. Это исправил в первом коммите.

Затем, мне там же не понравились две вещи:

  1. Отдельный запрос только для того, чтобы узнать количество результатов
  2. Во время выполнения цикла количество элементов может измениться, и это надо учитывать

Так что вторым коммитом идёт моя реализация этого метода

@hdk5
Copy link
Copy Markdown
Contributor Author

hdk5 commented Mar 19, 2018

Накосячил с мержем в свой форк, прошу прощения. К ПРу относятся три последних

@python273
Copy link
Copy Markdown
Owner

Может еще посмотришь execute версию? Думаю там тоже можно count_diff сделать

@hdk5
Copy link
Copy Markdown
Contributor Author

hdk5 commented Mar 20, 2018

Посмотрю

@hdk5
Copy link
Copy Markdown
Contributor Author

hdk5 commented Mar 20, 2018

Теперь код внутри передаваемой на сервер функции аналогичен тому, что внутри get_all_slow_iter с ограничением на 25 вызовов.
А методы get_all_iter и get_all_iter_slow отличаются двумя строчками, одна из которых в докстринге. Это исправь сам тот вид, который сочтёшь нужным

Comment thread vk_api/tools.py Outdated
var params = %(values)s,
calls = 0,
items = [],
count, new_count, count_diff, response;
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Может чтобы не копировать логику в python функцию, в аргументы добавить count? Тогда на первом шаге вк функция будет вызываться с count == None, а дальше с count из ответа

Copy link
Copy Markdown
Owner

@python273 python273 Mar 20, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+ offset. Еще можно возвращать need_more с true, если нужно еще раз вызывать вк функцию. Тогда будет:

values['offset'] = 0

count = None
need_more = True

while need_more:
    response = ...(..., count=count)
    need_more = response['need_more']
    values['offset'] = response['offset']
    count = response['count']
    ...

@hdk5
Copy link
Copy Markdown
Contributor Author

hdk5 commented Mar 20, 2018

Не совсем понимаю, зачем need_more, если всё равно сравнение count и offset должно идти правильно

@hdk5
Copy link
Copy Markdown
Contributor Author

hdk5 commented Mar 20, 2018

А вообще, я тут осознала, что если удалить некоторые старые результаты и добавить новые так, что их количество не изменится, то правильность обхода будет всё равно нарушена. Тут уж, если по хорошему, надо смотреть на id у результатов, когда они есть

@hdk5
Copy link
Copy Markdown
Contributor Author

hdk5 commented Mar 20, 2018

И ещё, если метод вызвался с одними параметрами в один момент, не значит что в следующую секунду я не попаду в чс/альбом будет удалён/etc.

Ух, сколько проблем то.

Comment thread vk_api/tools.py Outdated
count_diff = new_count - count;
var response = API.%(method)s(params),
new_count = response.count,
count_diff = (count == null : 0 ? new_count - count);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

разве не something ? iftrue : iffalse?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Да, точно

@python273
Copy link
Copy Markdown
Owner

Не совсем понимаю, зачем need_more, если всё равно сравнение count и offset должно идти правильно

Ну я имел в виду убрать логику count_diff из python функции, чтобы оно не дублировалось

если удалить некоторые старые результаты и добавить новые так, что их количество не изменится

Хм, мне кажется такое не особо вероятно. Максимум первые X итемов будут не актуальные, но это уже скорее всего будет скравлено в следующие разы (если вообще нужно получать обновления)

И ещё, если метод вызвался с одними параметрами в один момент, не значит что в следующую секунду я не попаду в чс/альбом будет удалён/etc.

Ну тоже не сильно вероятно. В любом случае нужно ловить ошибки при кравлинге

@hdk5
Copy link
Copy Markdown
Contributor Author

hdk5 commented Mar 20, 2018

Ну я имел в виду убрать логику count_diff из python функции, чтобы оно не дублировалось

Оно должно быть в обоих местах. Изменение набора может произойти как в vk-функции (что тоже маловероятно), так и в питоновской функции, пока что-то происходит между yield.

@python273
Copy link
Copy Markdown
Owner

так и в питоновской функции, пока что-то происходит между yield.

Но если возвращать последний offset из вк функции и перезаписывать в values, то в python функции count_diff не нужен, не?

@hdk5
Copy link
Copy Markdown
Contributor Author

hdk5 commented Mar 20, 2018

Да, точно, теперь понимаю

@python273
Copy link
Copy Markdown
Owner

Там еще предложение есть: #122
start_message_id ломает проверку offset + max_count > count. И с отрицательным offset проверка не будет работать. Наверное более универсально будет проверять len(items) < max_count, но так лишний запрос будет, если общее количество кратно max_count. Либо сразу 2 проверки делать 🤔

@hdk5
Copy link
Copy Markdown
Contributor Author

hdk5 commented Mar 21, 2018

А не получится ли доработать функции так, чтобы была возможность указать, что требуется получать итемы с отрицательным оффсетом: добавить аргумент, за это отвечающий, и исправить сами функции?

@hdk5
Copy link
Copy Markdown
Contributor Author

hdk5 commented Mar 21, 2018

То есть, что-то вроде этого: с оффсетом работать как и раньше, к апи обращаться с отрицательным оффсетом, если нужно, заканчивать всё, если ответ пустой

Comment thread vk_api/tools.py Outdated
count_diff = new_count - (count or new_count)

if new_count == 0:
break
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А для чего эта проверка?

Comment thread vk_api/tools.py Outdated
yield item

if limit and items_count >= limit:
if len(response_items) < max_count:
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if len(items) < max_count:
Вроде при прошлой проверке если бы добавился новый итем, то остановилось бы из-за items = response[key][count_diff:]

@python273
Copy link
Copy Markdown
Owner

Отрефакторил, чтобы было проще понять что происходит. Можешь посмотреть все ли ок и я мержну

@python273
Copy link
Copy Markdown
Owner

negative_offset вместе с messages.getHistory + start_message_id не совсем верно работает. В первом запросе загрузит (max_count - 1) сообщений после start_message_id и только потом будут сообщения до start_message_id.

Но не уверен нужно ли фиксить. Можно начинать с -max_count смещения, но тогда сообщение с айди start_message_id не будет в items. Хотя вроде и не должно быть 🤔

Интересно есть ли у других методов отрицательный offset

@hdk5
Copy link
Copy Markdown
Contributor Author

hdk5 commented Mar 22, 2018

Но не уверен нужно ли фиксить. Можно начинать с -max_count смещения, но тогда сообщение с айди start_message_id не будет в items. Хотя вроде и не должно быть 🤔

Да, всё так на самом деле

Comment thread vk_api/tools.py Outdated
)

items = response['items']
items = response[key]
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Функция всегда 'items' возвращает

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ну вроде бы и да, но изначально этот метод принимал ключ как параметр. Сам я сходу не нахожу методов апи, возвращающих массив под каким-то иным именем.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Где-то было users, но я не про это. Тут вызывается вк функция, она всегда items возвращает. В вк функции используется key

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А, точно, не обратил внимания

Comment thread vk_api/tools.py
yield item

if len(response_items) < max_count:
if len(response_items) < max_count - count_diff:
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Разве это не должно исправить преждевременный выход?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ну там уже проверка response_items вместо items, так что, как я понимаю, не нужно вычитать count_diff

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Да, точно, не обратил внимания

@python273
Copy link
Copy Markdown
Owner

^ там выше 2 коммента к коду

Comment thread vk_api/tools.py Outdated
ri = response.%(key)s.slice(count_diff);
items = items + ri;
offset = offset + params.count + count_diff;
if (ri.length < params.count - count_diff) {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Но тогда здесь вычитать count_diff всё же нужно

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Точно, там хотел немного по другому сделать

@python273
Copy link
Copy Markdown
Owner

@hdk5 можешь посмотреть все ли ок и мержну

@hdk5
Copy link
Copy Markdown
Contributor Author

hdk5 commented Mar 23, 2018

Вроде всё работает как ожидается 👍

@python273 python273 merged commit c3b4f6f into python273:master Mar 23, 2018
@xkord
Copy link
Copy Markdown
Contributor

xkord commented Mar 26, 2018

Какое ожидаемое поведения для negative_offset = True, при условии, что выставлен start_message_id > 0 ?
В моем понимании, если значение start_message_id > 0, то, например, для messages.getHistory, tools.get_all должен вернуть историю начиная со start_message_id и до последнего сообщения в переписке. В текущей реализации это не работает. Возвращается история c самого начала и до start_message_id включительно.

r = tools.get_all('messages.getHistory', 200, {'user_id': user_id, 'start_message_id': 5}, negative_offset=True) 
print(json.dumps(r, ensure_ascii=False, indent=4))

В данном примере возвращаются сообщения с идентификаторами с 1 по 5.
Спасибо.

@hdk5
Copy link
Copy Markdown
Contributor Author

hdk5 commented Mar 26, 2018

Какое ожидаемое поведения для negative_offset = True, при условии, что выставлен start_message_id?

Получение сообщений от start_message_id (не включительно) до наиболее нового (включительно)

@xkord
Copy link
Copy Markdown
Contributor

xkord commented Mar 26, 2018

Значит, вероятно, в текущем алгоритме есть ошибка.

@hdk5
Copy link
Copy Markdown
Contributor Author

hdk5 commented Mar 26, 2018

Да, действительно. get_all_slow работает правильно, сейчас посмотрю что не так с execute

Comment thread vk_api/tools.py
values['count'] = max_count

items_count = 0
offset = 0
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

        offset = max_count if negative_offset else 0

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Сделаешь PR?

@sakost
Copy link
Copy Markdown
Contributor

sakost commented Jul 2, 2019

Алгоритм с exeute по-прежнему работает неверно :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants