gifts2017

Быстрый поиск телефонов

Опубликовал Олег Пономаренко (O-Planet) в раздел Программирование - Работа с интерфейсом

Как двадцати операторам, не подвешивая друг друга, быстро находить телефонный номер по первым продиктованным цифрам, когда база номеров - от 50 тыс...

Потратил час на спор с клиентом, что 1С работает медленнее, чем его база на Oracle, поэтому, обеспечить одновременную, безглючную работу нескольких операторов, чтобы они, вводя номер телефона, по первым цифрам получали в выпадающем списке подходящие номера, нельзя... Все бы ничего, но

1. номеров может быть много... десятки тысяч... сеть пиццерий в Санкт-Петербурге, как ни как

2. мое неумение решить эту проблему грозило срывом хорошего договора

В конечном итоге, убедили клиента, что, хотя это и сложно, но проблему решим. Договор заключили. А вечером действительно решили вопрос :)

Всего-то нужно было - посмотреть на вопрос не глазами клиента а нашими, т.е., программистов. Чем грузится база? Запросами к ней и блокировками таблиц. Значит, нужно большую часть работы повесить не на сервер, а на клиентское приложение! 

И так, простой метод:

1. по первой цифре отбираем в запросе нужные нам номера

2. все последующие цифры - это запрос не к базе, а к списку уже отобранных нами номеров

Осталось немного "косметики". Проблема: пока вводятся цифры в поле ввода, никакая обработка ожидания не срабатывает. Как быть? Тот франч, что был до нас и потерял этот заказ, не предложил решения.  

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

- У Вас нет сенсорных экранов? Но ведь будут однажды!

- Да, конечно когда-нибудь будут...

Как я люблю это наше "надо прозапас"! И приятно, что наша небольшая супер команда оказалась хитрее крупного франча с филиалами во многих городах... :)

В общем, просто делюсь хорошим настроением и небольшой фичей, которую, если у кого похожая задача возникнет, не придется делать самому. В прилагаемой базе сгенерировано 50 тыс. номеров. Проверьте скорость работы. Можно и в сети.

"Ну а как быть, если номеров несколько миллионов?" - спросит кто-то

Не страшно! (Наверное)

Вариантов вижу 2, по крайней мере.

1. Использовать дополнительные поля в справочнике телефонов для отбора с включенной сортировкой. В частности: "Первый символ", "Два первых символа", "Три первых символа". Наверное, стоит все-таки обращаться к базе, пока длина введенной части не более 3-х символов, а вот потом уже работать со сформированным списком. Но по поводу этого готов услышать "за" и "против"

2. Использовать локальную базу номеров, выгруженную в виде того же dbf, и обращаться к ней на клиентской машине. При этом, dbf-ок можно иметь несколько. Опять же, по первому (двум) символу в номере.

Скачать файлы

Наименование Файл Версия Размер
Пример с 50 тыс. номерами 33
.zip 2,04Mb
02.09.12
33
.zip 2,04Mb Скачать

См. также

Подписаться Добавить вознаграждение
Комментарии
1. Misha ⁠ (Magister) 03.09.12 00:22
Плюс за оригинальное решение проблемы поля ввода :)

Собственно по алгоритму поиска - мне кажется, не стоит искать сразу после первой цифры. Вероятность, что при этом будет найден именно нужный телефон ничтожна, а нагрузку на базу это создаст немаленькую.
Разве что это требование заказчика.
Но и тогда лучше сделать типа ВЫБРАТЬ ПЕРВЫЕ 100.
2. Доржи Балбаров (Angeros) 03.09.12 05:04
Думаю что поле ввода можно было реализовать с клавиатуры... отдельно ввод, отдельно форма с вариантами... Ну и да я согласен с (1)номеров менее 4ех чисел ну хотя-бы 3ех... можно сделать.
3. Василий Антонов (khaoos) 03.09.12 05:17
А что не так с полем ввода? При наборе символов в поле ввода при малейшей задержке возникает событие "Автоподбор текста". Еще бы посоветовал навесить индекс на поле "номер телефона" в БД. Правда, в вашем решении он бесполезен, так как по одной цифре БД его точно не будет использовать.
4. Roman Biblbox (mr zafod) 03.09.12 05:43
Тоже не вижу проблемы - есть автоподбор текста, есть менеджер временных таблиц для запросов, есть индексирование. Подобную задачу помню решал еще на 8.1 лет 5 назад и база номеров тоже была огромной (около 100 000) - все решилось за 3-4 часа без взрыва мозга. А там помимо выборки стояла еще и реальная проблема - формат номеров, коих было великое множество.
Вы извините, но когда я вижу подобные "проблемы" - я начинаю понимать, почему у заказчиков такое предвзятое отношение к 1С, франчам и большинству специалистов 1С.
5. Олег Пономаренко (O-Planet) 03.09.12 05:45
(3) Ну, при использовании этого метода, конечно, будет все сложнее, но не намного. По крайней мере, нужно сравнивать ту строку, что сейчас в поле ввода с той, что в последний раз была отработана. Т.е., пара лишних переменных...
6. Олег Пономаренко (O-Planet) 03.09.12 06:03
(4) А что там 3-4 часа было делать?

Проблемы, на самом деле, есть.

Вот вопросы, которые я задаю себе, думая об этой задаче, и которые, я уверен, задаст заказчик впоследствии:

1. Номера бывают городские и мобильные, как сократить ввод мобильного номера? Цифра "8", по сути, загонит все мобильные в мой список.
2. И опять же, номер оператор... 8987 - это МТС у нас в городе. Несколько сот тысяч абонентов подключено на номер, начинающийся с этих цифр. Тут я соглашаюсь с (1): нужно подумать, как это оптимизировать.
3. А что если номеров будет не 50, а 500 тыс? И заказчик уже на это намекал. Реально ведь, чтобы 500 тыс. питерцев заказали пиццу!

Т.е., решение задачи требует оптимизации. И тут без выноса мозга, похоже, не обойтись.

На самом деле, заказчик сформулировал задачу достаточно однозначно: общая база 1С (не управляемые формы), эмуляция локальной сети через интернет подключение, несколько десятков операторов. Телефонных номеров - много (весь С-П). Нужно чтобы все операторы могли работать одновременно, без каких-либо тормозов.
7. Василий Антонов (khaoos) 03.09.12 06:44
(6) O-Planet, можно посоветовать префиксные цифры для сотовых хранить в отдельном столбце. Там где делаю заказы обычно, "8"-ку для сотовых номеров не нужно указывать: логичная оптимизация :). При показе пользователю "склеивать" префикс и его номер. При поиске же префикс может послужить дополнительным фильтром для найденных номеров: но поиск по нему бы не запускался. Но если в базе уже много номеров, может быть рутинным решение выглядеть по внедрению этой оптимизации :)
8. Roman Biblbox (mr zafod) 03.09.12 06:59
(6)О какой оптимизации идет речь? Пара лишних переменных в случае такой "тяжелой" задачи - думаю не проблема. Оптимизация здесь может быть только в том, чтобы:
1) все номера хранить и вводить без восьмерки
2) добавить измерения с индексацией по первым 3 и 3-6 символам номера
Для выборки использовать автоподбор по первым 3, далее 6 символам (благо количество введенных символов можно узнать без проблем) использую запрос с ВТ и индексами (и менеджером, чтобы по 100 раз в базу не лазить).
Все!!! Какая еще здесь может быть оптимизация? Есть желание - навешайте триггеров в postgre (oracle), потрясите планы запросов (хотя тут запрос линейный). Мы всегда ограничены платформой - не стоит об этом забывать!
AlX0id; khaoos; +2 Ответить
9. Дмитрий Чекунов (cdb) 03.09.12 17:31
Проблема: пока вводятся цифры в поле ввода, никакая обработка ожидания не срабатывает.
Для того что бы система дала обработать изменение после ввода любово символа (1-го, 2-го и т.д.) можно использовать элемент ActiveX к примеру MS Forms 2.0 TexBox. При каждом вводе символа будет отрабатывать событие ПриИзменении().
10. Евгений Кузнецов (kuzev) 04.09.12 15:40
При наборе цифр сколько номеров телефонов должно быть в отобранном списке? Разумное значение какое?
Мне кажется нет смысла "отображать" более нескольких десятков номеров. В этом случае можно завести отдельную таблицу (регистр) со значениями первых уникальных n-цифр (где n>3...5) номеров при условии, что таких номеров больше некого порога (например, 100). Сначала поиск осуществлять по ней, а как только значений не будет найдено можно лезть в общую таблицу, где записей с первыми n-цифр будет меньше порога.
11. kiril lipatov (kilokilo) 05.09.12 12:00
Телефоны - в текстовый файл. Регулярные выражения. Отработает за < 1 сек.
Но оперативной памяти на локальной машине должно быть достаточно - весь текст в памяти.
У меня 1С сыпалась при 2 000 000 строк на 2Гб оперативки на 32бит WinXP

Если на БД - то вынести телефоны на SQL базу, работающую в ОЗУ.. MySQL, например. И организовать доступ к данным через web-сервис к этой базе из 1С. И, опять же, в запросе использовать регулярные выражения, что позволит искать данные в любой части номера..

Если делать на 1С - можно попробовать иерархический справочник (иерархия элементов), 3 уровня.
1й уровень - код страны, 2й - код города/оператора, 3й - телефон..
Выборка на одно уровне иерархии происходит быстрее.

В крайнем случае - создать у регистра, где хранят номера, индексированное поле, куда писать нормализованные номера - только циферки, без лишних пробелов, черточек, тире.. И запрос с инструкцией ПОДОБНО:
ВЫбРАТЬ Номер Из Регистр ГДЕ Номер ПОДОБНО %ном% ИЛИ Номер ПОДОБНО %ном ИЛИ Номер ПОДОБНО ном%"
Diversus; +1 Ответить
12. Андрей Овсянкин (Evil Beaver) 01.11.12 16:36
И что, если просто проиндексировать поле Телефон и включить управляемые блокировки, то работает медленно? Там второй Пентиум на сервере?
13. Анатолий Васильченко (zveruga56) 07.11.12 11:12
Неплохо бы предусмотреть поиск по подстроке.
Набрал, к примеру, 888, а в списке:

+79128882931
+79878470888

Для этого надо создать несколько индексных таблиц для отбора номеров по подстроке из 3,4,5 символов.
При добавлении номера в базу - прописывать его и в индексные таблицы, со всеми возможными подстроками поиска.

P.S. Пора уже с call-центром соединять.. ;-)