Как стать автором
Обновить

VoIP телефония. Asterisk. Нестандартный подход ко всему. Часть 2

Время на прочтение16 мин
Количество просмотров12K

Продолжаем наш рассказ о модификации движка для VoIP оператора связи.


В первой части мы рассказали о начальной структуре базы данных и настройке Asterisk для обслуживания вызовов, с мониторингом состояния вызова. В этой части мы затронем такие вещи как тарификатор, LCR, биллинг и геолокация.


Тарификатор


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


Вот выдержка из тарифного плана оператора связи:


"Minimal Duration- 1 second"
"Billing increment- 1 second"
"USA -6/6"
"Mexico   60/60"
"Gambia   60/1"
"Tonga All (Prefix 676) - 60/60"
"Vanuatu All (Prefix 678)- 60/60 "
"Samoa (Prefix 685) - 60/60"
"Papua New Guinea (Prefix 675)- 60/60 "
"Nauru All (Prefix 674)- 60/60 "

Как мы видим, минимальное время разговора равно одной секунде, а стоимость разговора вычисляется из количества потраченных секунд (1/1), звонок в Соединённые Штаты Америки тарифицируется с шагом в 6 секунд(6/6), звонок в Мексику тарифицируется с шагом в 60 секунд, т.е. поминутно(60/60). Также может использоваться формула 60/1, что означает посекундную тарификацию звонка, но с полной оплатой первой минуты разговора. Например если минута разговора стоит 0.37USD и вы разговаривали 28 секунд, то стоимость вашего звонка составит 0.37USD, а если вы разговаривали 76 секунд, то стоимость вашего звонка составит (0.37/60)*76USD.


Оператор фиксированной, мобильной или VoIP связи, предоставляя вам поминутную тарификацию в регионы с посекундной оплатой разговора, на данной разнице зарабатывает себе на хлеб. Маржа конечно небольшая, но совместно с повышением тарифа для конечного пользователя, получается как в анекдоте "двадцать старушек — рубль". И совсем немногие операторы позволяют себе продавать посекундную тарификацию конечному пользователю.


Тарифные сетки операторов основаны на префиксной адресации вызова. Префикс обычно представляет собой несколько первых цифр телефона в международном стандарте. Это означает, что у каждого конкретного оператора звонок по определенному направлению может отличаться в разы. Это происходит как из-за способа доставки звонка до вызываемого абонента, так и из-за внедрения в номерную ёмкость локальных операторов связи, так называемых "премиум" или "специальных" сервисов. "Премиум" сервисами обычно называют справочные(где купить, как проехать и т.д.), либо развлекательные сервисы(гороскопы, магазин на диване, секс по телефону и т.д.), доступ к которым предоставляется на платной основе по повышенным тарифам. Если оператор связи не контролирует исходящие звонки из своих систем или несвоевременно обновляет тарифные планы своих партнёров, то известны случаи гигантских долгов из-за случайного разрешения звонков на "премиум" сервисы без контроля личного счёта клиента.


Как это происходит в реальной жизни?


Переделывая "движок" оператора мы столкнулись с тем, что старый "движок" не отслеживал направления звонков и тарифицировал клиента "по факту", с ограничением времени звонка в 3600 секунд. Т.е. клиент мог позвонить на телефон "премиум" сервиса и "завесить" сессию на 1 час. При стоимости звонка в 5 долларов за минуту, оператор попадал на 300 долларов в час. А так как количество одновременных вызовов было не ограничено, то потери могли составлять бОльшие суммы. В связи с тем, что операторы связи только выходящие на рынок пытаются привлечь новых клиентов, они дают "тестовый" доступ новым пользователям на определённую виртуальную сумму. Пользователь совершает звонок в нужное ему место, оценивает качество связи, и если всё хорошо, то начинает пополнять свой "личный" кошелёк у этого оператора связи. Данным типом доступа пользуются фродеры, которые находятся в сговоре с хозяевами "премиум" сервиса. Фродер используя бреши в системе тарификации операторов, совершает несколько звонков на платные сервисы, тем самым выставляя оператора на деньги. При этом стоимость звонка фродера на платный сервис практически равна нулю, а прибыль может достигать огромных сумм. Оператор связи обнаруживает проблему либо на утро, либо после получения оповещения о исчерпании денег на своём счету. Оспорить совершенный звонок, который прошёл через цепочку операторов и достиг "премиум" сервиса, практически невозможно, т.к. оплата за сессию идёт по всей цепочке операторов.


Рассмотрим примеры "премиум" сервисов и как они выглядят в тарифной сетке.


prefix pricerub note tarif_name
37122 1,001 LATVIA Mobile VOICETRADEC
371227 0,8439 LATVIA Other 4, Latvia VAS IPRS VOICETRADEC
3712270 34,321 LATVIA Latvia-Mobile, Latvia Premium, Latvia VAS IPRS VOICETRADEC
3712272 1,001 LATVIA LATVIA NGN, Latvia mobile Bite, Latvia VAS IPRS VOICETRADEC
3712274 32,812 LATVIA LATVIA NGN, Latvia VAS IPRS VOICETRADEC
3712277 1,0226 Latvia Mobile — Master, Latvia mobile Master Telecom, LATVIA Radiocoms Mobile, Латвия моб.Master Telecom VOICETRADEC
3712278 37,181 Latvia Premium, LATVIA Radiocoms Mobile, Latvia Services ECO Networks, Latvia VAS IPRS, Латвия моб.ECO Solutions VOICETRADEC
3712279 37,181 LATVIA Mobile, Latvia Premium, Latvia Services ECO Networks, Latvia VAS IPRS, Латвия моб.ECO Solutions VOICETRADEC

Если внимательно посмотреть на таблицу, то мы увидим, что номер 37122705678 попадает под три тарифа 37122,371227,3712270. Если некорректно обработать начало номера или вовремя не обновить тарифный план, то вместо ожидаемого звонка за рубль или 84 копейки, мы получим звонок с ценой больше 30 рублей за минуту. Именно данной лазейкой и пользуются злоумышленники. Поэтому для исключения таких вариантов развития событий, мы разделили все префиксы на 14 категорий.


id category description
1 FIXED Стационарные номера телефонов
2 PREMIUM Премиум сервисы(гороскопы, секс услуги, платная справочная информация и т.д.)
3 OffNet Звонки из роуминга
4 OnNet Звонки внутри сети
5 OTHER Прочие типы звонков
6 MOBILE Мобильные номера телефонов
7 PAGER Сервисы коротких сообщений
8 TOLLFREE Сервисы разговоров, где за вызов платит вызываемый номер
9 VOIP Интернет телефония
10 SATELLITE Спутниковая связь
11 NETWORK Местные операторы связи
12 PERSONAL Персональные "красивые" номера не привязанные к географическому региону
13 UNKNOWN Неизвестные телефонные коды
14 UNUSED Неиспользуемые телефонные коды

А когда запустили связку в работу, то просто ограничили тестовые звонки на часть спорных категорий. Если пользователь вносил свои деньги на счёт, то заблокированные категории автоматически открывались. Это снизило уровень фрода практически на 99%. Оставшийся процент подвисал в воздухе из-за временного лага в обновлении тарифов партнёров. При обновлении тарифной сетки те префиксы, которые не были определены в таблице, "выпадали" из общего списка и после анализа оператором, привязывались к нужной категории.


LCR(Least Cost Routing) — «маршрутизация по критерию наименьшей стоимости»


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


Тарифная сетка у нас уже была и в ней находилось около 700.000 записей.


Понятное дело, что поиск по 700.000 записей дело накладное, а с увеличением количества операторов, количество записей бы заметно подросло. Поэтому мы искали множество путей ускорения поиска маршрута в тарифной сетке.


Внимание! номер 79031210011 взят для примера и моим не является. Цены на разговоры в таблицах указаны от апреля 2016 года(последний дамп базы)


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


#Первый
select * from rates r where '79031210011' like CONCAT(r.prefix,'%') 
#Второй
select * from rates r where INSTR('79031210011',r.prefix) = 1

#Первый чуть быстрее, второй чуть медленнее

select prefix,pricerub,note,tarif_id from rates r where '79031210011' like CONCAT(r.prefix,'%');
/* Затронуто строк: 0  Найденные строки: 15  Предупреждения: 0  Длительность  1 запрос: 0,421 sec. */
select prefix,pricerub,note,tarif_id from rates r where INSTR('79031210011',r.prefix) = 1;
/* Затронуто строк: 0  Найденные строки: 15  Предупреждения: 0  Длительность  1 запрос: 0,453 sec. */

Ответ выглядел следующим образом:


prefix pricerub note tarif_id
7 11,72 Неопознанные коды 11
79 1,495 РОССИЯ МОБИЛЬНЫЕ 3
79 1,15 Россия (mob) — регион 11
7903 1,15 Россия (mob) — Билайн 11
79031 1,15 Москва (mob) — Билайн 11
7 0,715 RUSSIAN FEDERATION Fixed 5
7903 3,9326 RUSSIAN FEDERATION Mobile 5
7 0,742 RUSSIAN FEDERATION Fixed 6
7903 4,2294 RUSSIAN FEDERATION Mobile 6
7 1,6729 Russia Fixed 9
79 7,9731 Russia Mobile 9
7903 5,6999 Russia Mobile — Beeline 9
7 0,8027 Russia Fixed 10
79 1,457 Russia Mobile 10
7903 3,393 Russia Mobile — Beeline 10

Cкорость поиска в полсекунды(тестовая среда) не то чтобы совсем критична, но выглядит странно. Поэтому для оптимизации поиска мы вынесли поле prefix в отдельную таблицу, сделав его ключевым для таблицы rates


select * from rates_prefix r where '79031210011' like CONCAT(r.prefix,'%');
/* Затронуто строк: 0  Найденные строки: 4  Предупреждения: 0  Длительность  1 запрос: 0,172 sec. */



Как мы видим, скорость поиска выросла примерно в три раза. Что в принципе не так уж и плохо. Далее полученная таблица префиксов "пристыковывается" к таблице тарифов операторов, и из результирующей таблицы убираются лишние "короткие" префиксы. Там же пристыковывается таблица операторов и на выходе мы имеем полноценный список маршрутов с ценами и префиксами, который привязан к оператору связи.


call usp_asteriskfastpathtest('79031210011','test_user',0);
/* Затронуто строк: 0  Найденные строки: 17  Предупреждения: 0  Длительность  1 запрос: 0,140 sec. */

rate_prefix dial_string note rate_pricerub provider_id
79031 SIP/westcall/79031210011 Москва (mob) — Билайн 1,15 7
7903 SIP/sip.voicebuy.com/999279031210011 RUSSIAN FEDERATION Mobile 3,9326 11
7903 SIP/sbc.voxbeam.com/001110179031210011 Russia Mobile — Beeline 5,6999 8

Ну или например список маршрутов до отеля Crystal Hotel в Америке с номером 13606632262


rate_prefix dial_string note rate_pricerub provider_id
1360 SIP/sbc.voxbeam.com/001110313606632262 United States — OnNet — WA — 360 0,3305 8
1360 SIP/sip.voicebuy.com/999113606632262 UNITED STATES OF AMERICA Washington 0,3474 11
1360 SIP/91.190.132.39/010#13606632262 USA Other 0,4047 13

Естественно, при формировании списка дозвона, совместно с сортировкой префиксов в тарифной сетке используется довольно много дополнительных условий. Это и дата начала/конца действия тарифа, поддержка CLI, ручные блокировки и прочие. Финальная таблица перед занесением в базу дополнительно обрабатывается на задаваемое ограничение максимальной стоимости звонка. Нет смысла разрешать звонки за 300 рублей для пользователя у которого на счету всего 100 рублей.


Всё это накладывает свои издержки на производительность. На боевой системе мы получали примерно 50ms на запрос.


Биллинг


Как мы все понимаем, не бывает систем предоставления услуг без подсчёта стоимости предоставленных услуг. Мы долго думали, как наиболее оптимально контролировать состояние кошелька пользователя и нашли на наш взгляд компромиссное решение.


В конце первой части я описал настройку сервера Asterisk в плане добавления сервисных функций и функций контроля состояния канала. Эти же функции позволяют чётко отслеживать состояние вызова для клиента.


Как можно увидеть в нижеследующей таблице



у нас всегда есть информация о текущем тарифе оператора, валюте оператора, тарифе клиента, направлении и прочему. Что в свою очередь превращается в следующую таблицу



И именно dial_guid возвращается приложением make_a_route.py в контекст [make_a_call], а поле step используется для уточнения текущей итерации.


Когда Asterisk начинает подготавливать канал связи для соединения абонентов, он вызывает приложение create_channel_record.py, которое формирует в таблице CDR пустую запись, в которой нет никакой информации кроме времени создания канала, идентификатора пользователя и dial_guid+step. Когда вызываемый пользователь поднимает трубку, вызывается приложение predial.py, которое заполняет поля таблицы ответственные за время поднятия трубки и тарификацию вызова. В случае корректного завершения разговора или возникновения ошибки, вызывается приложение hangup.py, которое "закрывает" CDR запись в базе, заполняя поле со временем окончания разговора. Таким образом получается, что ошибочные звонки, которые по какой-то причине не были совершены, не попадают в биллинг пользователя, но остаются в логах системы. На таблицу с временной CDR информацией установлен триггер, который ожидает изменений строк, где время поднятия трубки и время окончания разговора не равны нулю. Как только данный триггер видит описанное выше условие, он переносит данные из временной CDR таблицы в основную и записывает клиенту на счёт израсходованную сумму.


К слову говоря, есть еще одна таблица в которой хранятся названия каналов обслуживающих текущие вызовы и привязанные к dial_guid. В связи с тем, что мы видим в realtime все текущие разговоры в базе данных, в базу данных был введен триггер срабатывающий раз в 5 секунд и соотносящий текущие осуществляемые разговоры с тарифами на них и остатком средств на счёте клиента.


Как только денежных средств на счёте клиента остаётся менее чем на 1 минуту разговора, триггер помещает в специальную таблицу номер канала, который инициировал вызов. Служебный appication server, находящийся на каждом из Asterisk серверов, мониторит данную таблицу. Как только он видит там строку адресованную в его адрес, вызывается приложение Originate с перенаправлением на контекст с фразой "недостаточно денежных средств" и разговор завершается. После завершения разговора, срабатывают штатные процедуры изменяющие баланс клиента. Данная схема прекрасна тем, что отслеживает все осуществляемые с аккаунта клиента разговоры на всех серверах.


Мониторинг разговоров выглядит примерно так.




Мультивалютный пересчёт


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


Это делает простейший скрипт на Python


# -*- coding: utf-8 -*-

import urllib
from sqlconfig import *
import mysql.connector
import json

# Init mysql connection
cnx = mysql.connector.connect(**config)
cursor = cnx.cursor()
cursor.execute('SET AUTOCOMMIT=1;')
cursor.execute('SET collation_connection=\'utf8mb4_unicode_ci\';')

currency_pairs = [ ('EUR','USD'),('EUR','RUB'),('EUR','UAH'),('EUR','KZT'),('RUB','USD'),('RUB','UAH'),('RUB','KZT'),('USD','UAH'),('USD','KZT') ]
for base in currency_pairs:
    (fromcur,tocur) = base
    root_url = 'http://www.bloomberg.com/markets/api/security/currency/cross-rates/%s,%s'%(fromcur,tocur)
    f = urllib.urlopen(root_url)
    myjson = json.loads(f.read())
    pair = myjson[u'data']
    for fromcur in pair:
        for topair in pair[fromcur].items():
            (tocur,crossrate) = topair
            cursor.execute('INSERT INTO currency_cross (getcrosstime,from_currency_id,to_currency_id,crossrate) VALUES (now(),(select id from currency where iso="%s"),(select id from currency where iso="%s"),"%s")'%(fromcur,tocur,crossrate))
            print fromcur,tocur,crossrate
cnx.commit()
cursor.close()
cnx.close()

Он формирует таблицу кросскурсов на каждый день


From To ExchRate
USD EUR 0.9423
EUR USD 1.0612
RUB EUR 0.01581
EUR RUB 63.2363
UAH EUR 0.03409
EUR UAH 29.3352
KZT EUR 0.002831
EUR KZT 353.1992
RUB USD 0.01678
USD RUB 59.5889
RUB UAH 0.4639
UAH RUB 2.1556
RUB KZT 5.5854
KZT RUB 0.179
UAH USD 0.03618
USD UAH 27.6434
USD KZT 332.83
KZT USD 0.003005

Таким образом, в зависимости от основной валюты, в которой производится расчёт, мы можем пересчитывать средства клиента и приводить тарифы к нужной валюте.


Геолокация звонков


Геолокация довольно важная часть различных сервисов, которые общаются с клиентами по всему миру. Всегда приятно на телефоне видеть номер звонящего совпадающего с твоим местоположением. Как это работает ?


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


Крупные города (города миллионники) такие как Москва, Санкт-Петербург и прочие имеют семизначный план нумерации, города регионального значения — шестизначный, города областного значения — пятизначные и т.д.


Внутри номерного плана Российской федерации происходит деление на:


  • Федеральный округ
  • Город федерального значения
  • Город
  • Область
  • Район
  • посёлок, село, поселение и т.д.

Внутри номерного плана Соединённых Штатов Америки происходит деление на:


  • Area
  • State
  • District
  • County
  • City

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


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


Операторы IP телефонии предоставляющие свои тарифы, обычно включают в виде структурированного описания, местоположение которое обслуживает префикс.


Не будем ходить далеко и возьмём первые строки из операторского тарифного плана:


"prefix","comment","price","connect_cost","increment","custom","created_at",
"9375","AFGHANISTAN - CDMA","0.388125","0.0000","60","0","2015-10-11 23:21:51",
"9340","AFGHANISTAN - HERAT","0.388125","0.0000","60","0","2015-10-11 23:21:51",
"9360","AFGHANISTAN - JALALABAD","0.388125","0.0000","60","0","2015-10-11 23:21:51",
"9320","AFGHANISTAN - KABUL","0.388125","0.0000","60","0","2015-10-11 23:21:51",
"9330","AFGHANISTAN - KANDAHAR","0.388125","0.0000","60","0","2015-10-11 23:21:51",
"9350","AFGHANISTAN - MAZAR-E-SHARIF","0.388125","0.0000","60","0","2015-10-11 23:21:51",
"937","AFGHANISTAN - MOBILE","0.388125","0.0000","60","0","2015-10-11 23:21:51",
"9377","AFGHANISTAN - MOBILE - AREEBA","0.32751","0.0000","60","0","2015-10-11 23:21:51",
"9370","AFGHANISTAN - MOBILE - AWCC","0.32751","0.0000","60","0","2015-10-11 23:21:51",
"9378","AFGHANISTAN - MOBILE - OTHER CARRIERS","0.32751","0.0000","60","0","2015-10-11 23:21:51",
"9379","AFGHANISTAN - MOBILE - ROSHAN","0.310365","0.0000","60","0","2015-10-11 23:21:51",
"93","AFGHANISTAN - PROPER","0.388125","0.0000","60","0","2015-10-11 23:21:51",
"35568","ALBANIA - MOBILE - AMC","0.456165","0.0000","60","0","2015-10-11 23:21:51",
"35567","ALBANIA - MOBILE - EAGLE","0.452925","0.0000","60","0","2015-10-11 23:21:51",
"35569","ALBANIA - MOBILE - VODAFONE","0.47007","0.0000","60","0","2015-10-11 23:21:51",
"355","ALBANIA - PROPER","0.08046","0.0000","60","0","2015-10-11 23:21:51",
"3554","ALBANIA - TIRANE","0.08046","0.0000","60","0","2015-10-11 23:21:51",
"35541","ALBANIA - TIRANE","0.08046","0.0000","60","0","2015-10-11 23:21:51",
"35542","ALBANIA - TIRANE","0.03861","0.0000","60","0","2015-10-11 23:21:51",
"35543","ALBANIA - TIRANE","0.08046","0.0000","60","0","2015-10-11 23:21:51",
"35544","ALBANIA - TIRANE","0.08046","0.0000","60","0","2015-10-11 23:21:51",
"35545","ALBANIA - TIRANE","0.08046","0.0000","60","0","2015-10-11 23:21:51",
"35546","ALBANIA - TIRANE","0.08046","0.0000","60","0","2015-10-11 23:21:51",
"3554249","ALBANIA 0 OLO GROUP","0.04401","0.0000","60","0","2015-10-11 23:21:51",

"7997","RUSSIA (MOBILE)","0.07938","0.0000","60","0","2015-10-11 23:21:51",
"78182","RUSSIA - ARKHANGELSK","0.09558","0.0000","60","0","2015-10-11 23:21:51",
"73512","RUSSIA - CHELYABINSK","0.055755","0.0000","60","0","2015-10-11 23:21:51",
"74932","RUSSIA - IVANOVO","0.055755","0.0000","60","0","2015-10-11 23:21:51",
"73412","RUSSIA - IZHEVSK","0.055755","0.0000","60","0","2015-10-11 23:21:51",
"78432","RUSSIA - KAZAN","0.052515","0.0000","60","0","2015-10-11 23:21:51",
"73912","RUSSIA - KRASNOYARSK","0.052515","0.0000","60","0","2015-10-11 23:21:51",
"7813","RUSSIA - LENINGRAD REGION","0.055755","0.0000","60","0","2015-10-11 23:21:51",
"79","RUSSIA - MOBILE","0.07938","0.0000","60","0","2015-10-11 23:21:51",
"7964","RUSSIA - MOBILE - BEELINE","0.13311","0.0000","60","0","2015-10-11 23:21:51",
"7965","RUSSIA - MOBILE - BEELINE","0.13311","0.0000","60","0","2015-10-11 23:21:51",
"792","RUSSIA - MOBILE - MEGAFON","0.07938","0.0000","60","0","2015-10-11 23:21:51",
"791","RUSSIA - MOBILE - OTHER CARRIERS","0.07938","0.0000","60","0","2015-10-11 23:21:51",

1531,US,"United States - OnNet - NE - 531",0.008100,6,6,0.008100,Unchanged,USD,11-Apr-2016,22:00:00,18-Apr-2016,22:00:00
1603,US,"United States - OnNet - NH - 603",0.008100,6,6,0.008100,Unchanged,USD,11-Apr-2016,22:00:00,18-Apr-2016,22:00:00
1201,US,"United States - OnNet - NJ - 201",0.008100,6,6,0.008100,Unchanged,USD,11-Apr-2016,22:00:00,18-Apr-2016,22:00:00

Как можно увидеть из этих данных, существует привязка кода к стране и типу связи.


  • PROPER — Основной код страны
  • FIXED — фиксированная связь
  • MOBILE — мобильный оператор связи. обычно если известно его имя, то оно идёт следом
  • CITY — если код относится целиком к городу, то пишется его имя
  • OLO — аббревиатура используемая для обозначения локальных операторов(OTHER LOCAL OPERATOR)
  • OTHER — прочие виды связи
  • IPRS — индивидуальные премиум сервисы
  • PREMIUM — премиум услуги
    и т.д.

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


Вот наверное в принципе и всё, что можно описать полезного из проекта, который мы делали. От получения первой информации до запуска в тестовую эксплуатацию прошло примерно 3 месяца. Основное время было потрачено на обработку различных данных и отладку механизмов внутри базы данных. Например полный дамп сайта https://sanstv.ru/codes/, с сохранением его работоспособности для других пользователей, занял примерно четверо суток, а обработка данных около двух недель. Тоже самое с российскими префиксами и прочей служебной информацией. По сути проект писался сначала двумя людьми, потом присоединилось еще 2 человека. Основные проблемы проекта заключались в отсутствии описанного ТЗ и как в Пьеса. Технический долг изменением задач на лету. По началу даже показалось, что статья писана с этого проекта. Надеюсь описанные здесь методики и подходы будут полезны Вам в Ваших проектах.


Спасибо за потраченное на прочтение статей время.


© Aborche 2017
Aborche

Теги:
Хабы:
Всего голосов 10: ↑10 и ↓0+10
Комментарии12

Публикации

Истории

Работа

Data Scientist
61 вакансия
Python разработчик
137 вакансий

Ближайшие события