Идея: фильтрация "лишних" правил по критерию вхождения доменного имени правила в доменное имя другого правила
Добавлено: Вс дек 27, 2020 18:20
В списках для группы banner есть такие правила:
Проблемма:
Все эти правила эквивалентны правилу adriver.ru, так как если есть правило adriver.ru, то и домен и все его поддомены будут заблокированы. Т.е. кроме первого - все эти правила являются лишним балластом.
Все они перекрываются правилом adriver.ru. В итоге можно сэекономить длину списка, по которому система фильтрации ищет блокируемые домены и как следствие - сократить время на поиск по этому списку.
В общем, чем меньше правил в списке - тем быстрее работает система фильтрации.
Что хочу:
- экспортировать правило adriver.ru;
- игнорировать остальные правила, чьи домены являются поддоменами для adriver.ru.
Вариант решения "в лоб": добавить к "ненужным" правилам ответ "нет" через форму добавления новых правил.
Как следствие, при экспорте скрипт будет считать, что эти правила не входят в соответствующие группы и проигнорирует их. А я получу оптимизированный список.
Диллема: для других пользователей мои ответы "нет", для домена явно рекламного содержания, будут по меньшей мере "странными" и мой ник определят в "список игнорируемых пользователей".
Вариант решения "правильный": создать свой собственный список игнорируемых правил и при экспорте из DBL игнорировать правила из этого списка. В системе останутся ответы, которые означают именно то, что от них ожидается:
- да - "по адресу URI, которое соответствует правилу, расположено содержимое, характерное для указанной группы";
- нет - "по адресу URI, которое соответствует правилу, отсутствует содержимое, характерное для указанной группы".
Недостаток: это уже своя "система фильтрации списка фильтров" - некий сторонний костыль.
Вариант решения "идеальный": прямо в системе DBL ставить метки "игнорировать" для необходимых правил.
Чем больше пользователей отметят правило как "игнорировать", тем менее значимыми будут эти правила.
При экспорте:
- игнорировать правило, если у поравила есть метка "игнорировать" от себя;
- игнорировать правило, если у поравила есть метка "игнорировать" от более чем 20 других пользоватлей.
Спустя несколько лет отмечать такие "игнорируемые" правила как удалённые и больше не использовать.
Недостаток: данные в системе потенциально расширяются в экспоненциальной прогрессии (количество правил * количество пользователей), что чревато лишним расходом памяти при множественных повторениях одинаковых записей для разных пользователей.
Вариант решения самый идеальный (по моему мнению):
- для каждого правила создать атрибуты (добавить колонки в таблицу Rules):
- при добавлении нового правила - выполнять для него expandRule(Id);
- при экспорте SQL > XML, в запись <record> добавлять атрибут <rootid> и <ruleisdomain>;
- в скрипте "dbl_expand":
На выходе получается система автоматической оптимизации списка правил, которая исключит из выходящего списка те правила, которые являются балластом по той причине, что никогда не будут применены, так как они перекрываются другими правилами.
Такая система:
- обрабатывает только правила типа "*.urls";
- игнорирует правила, у которых не указано имя домена (правила типа "/banner.gif");
- фильтрует только правила с таким доменом, который входит в имя другого домена, для которого в базе есть точное правило Rule==Domain (если есть правила "ad.adriver.ru/cgi-bin", "content.adriver.ru/plugins/autoUpdate.adriver.js" и "https://www.adriver.ru/index.html", то они будут проигнорированы только в том случае, если в базе есть правило "adriver.ru", у которого строка правила является также и именем домена).
Код: Выделить всё
adriver.ru
ad.adriver.ru
ad.adriver.ru/cgi-bin
ad.adriver.ru/cgi-bin/click.cgi
ad.adriver.ru/cgi-bin/erle.cgi
ad.adriver.ru/cgi-bin/rle.cgi
content.adriver.ru/plugins/autoUpdate.adriver.js
Все эти правила эквивалентны правилу adriver.ru, так как если есть правило adriver.ru, то и домен и все его поддомены будут заблокированы. Т.е. кроме первого - все эти правила являются лишним балластом.
Все они перекрываются правилом adriver.ru. В итоге можно сэекономить длину списка, по которому система фильтрации ищет блокируемые домены и как следствие - сократить время на поиск по этому списку.
В общем, чем меньше правил в списке - тем быстрее работает система фильтрации.
Что хочу:
- экспортировать правило adriver.ru;
- игнорировать остальные правила, чьи домены являются поддоменами для adriver.ru.
Вариант решения "в лоб": добавить к "ненужным" правилам ответ "нет" через форму добавления новых правил.
Как следствие, при экспорте скрипт будет считать, что эти правила не входят в соответствующие группы и проигнорирует их. А я получу оптимизированный список.
Диллема: для других пользователей мои ответы "нет", для домена явно рекламного содержания, будут по меньшей мере "странными" и мой ник определят в "список игнорируемых пользователей".
Вариант решения "правильный": создать свой собственный список игнорируемых правил и при экспорте из DBL игнорировать правила из этого списка. В системе останутся ответы, которые означают именно то, что от них ожидается:
- да - "по адресу URI, которое соответствует правилу, расположено содержимое, характерное для указанной группы";
- нет - "по адресу URI, которое соответствует правилу, отсутствует содержимое, характерное для указанной группы".
Недостаток: это уже своя "система фильтрации списка фильтров" - некий сторонний костыль.
Вариант решения "идеальный": прямо в системе DBL ставить метки "игнорировать" для необходимых правил.
Чем больше пользователей отметят правило как "игнорировать", тем менее значимыми будут эти правила.
При экспорте:
- игнорировать правило, если у поравила есть метка "игнорировать" от себя;
- игнорировать правило, если у поравила есть метка "игнорировать" от более чем 20 других пользоватлей.
Спустя несколько лет отмечать такие "игнорируемые" правила как удалённые и больше не использовать.
Недостаток: данные в системе потенциально расширяются в экспоненциальной прогрессии (количество правил * количество пользователей), что чревато лишним расходом памяти при множественных повторениях одинаковых записей для разных пользователей.
Вариант решения самый идеальный (по моему мнению):
- для каждого правила создать атрибуты (добавить колонки в таблицу Rules):
- ruleIsDomain - флаг, если 1 - текст правила является именем домена (rule is domain). Значение по умолчанию - 0;
- Domain - имя домена из текущего правила;
- RootRuleId - идентификатор правила, в домен из которого входит домен данного правила.
- getDomainFromRule(rule) - возвращает имя домена из Rule (уверен, для этого в Perl есть стандартные библиотеки обработки URI, если домен не указан - возвращает пустую строку);
- expandRule(id) - анализирует Rule и заполняет атрибуты ruleIsDomain/Domain/RootRuleId;
- expandAllRules() - делает expandRuleдля всех правил.
- findRootId(domain) - ищет идентификатор правила, в домен которого входит domain.
- при добавлении нового правила - выполнять для него expandRule(Id);
- при экспорте SQL > XML, в запись <record> добавлять атрибут <rootid> и <ruleisdomain>;
- в скрипте "dbl_expand":
- перед анализом XML-файла, вначале пройтись по этому файлу и извлечь Rule тех правил, у которых RuleIsDomain=1. Это будет "эталонный список балластных правил";
- перед записью правила в файл "+urls", проверить домен из Rule на вхождение в домены из "эталонного списка балластных правил". Если домен из правила или родительский домен из правила есть в этом списке - игнорировать такое правило и не заносить в файл "+urls".
Код: Выделить всё
proc ballastRules::RegisterInvalidDomainNameInRule {rule} {
return [sql "INSERT OR IGNORE INTO _invalidDomainName (Rule) VALUES ('$rule'); SELECT Id FROM _invalidDomainName WHERE Rule='$rule';"]
}
proc ballastRules::getDomainFromRule {rule} {
set rule [string trimleft $rule "*."]
if {[catch {array set vector [uri::split $rule]} res]} {
set invalidRuleId [RegisterInvalidDomainNameInRule $rule]
puts "WARN: [namespace current]::getDomainFromRule: fail get domain name from rule. InvalidRuleId = $invalidRuleId, Rule = {$rule}"
return ""
}
return $vector(host)
}
proc ballastRules::ruleIsIp {rule} {
if {[::ip::version $rule] != -1} {return 1}
return 0
}
proc ballastRules::FindRootId {domain} {
set hostsList [split $domain "."]; # разделяем домен на список хостов
set rootId ""; # вначале идентификатор правила пуст
set rootDomain "";
for {set i 0} {$i < [llength $hostsList]} {incr i} {
set rootHosts [lrange $hostsList $i end]; # берем вначале все хосты, потом все кроме первого, далее все кроме первых двух и т.д.
set domain [join $rootHosts "."]; # собираем список хостов в имя домена, разделяя имена хостов символом "точка"
set sqlCmd "SELECT Id, Domain FROM Record WHERE RuleIsDomain=1 AND Domain='$domain' LIMIT 1 ;"
lassign [sql $sqlCmd] rootId rootDomain; # ищем только среди правил, у которых Domain=Rule
if {$rootId ne ""} break; # останавливаем поиск как только нашли первое совпадение
}
return [list $rootId $rootDomain]
}
proc ballastRules::ExpandRuleInit {id Rule} {
if {[ruleIsIp $Rule]} {return {}}; # если Rule является IP-адресом - пропускаем обработку
set domain [getDomainFromRule $Rule]; # вытаскиваем имя домена из правила
if {$domain eq ""} return; # если в Rule отсутствует имя домена - пропускаем такое правило
set RuleIsDomain 0; if {$Rule eq $domain} {set RuleIsDomain 1}; # если строка Rule равна строке $domain - выставляем флаг
sql "UPDATE Record SET Domain='$domain', RuleIsDomain=$RuleIsDomain, RootRuleId=0 WHERE Id=$id;";
return $domain
}
proc ballastRules::ExpandRuleRoot {id domain} {
if {$domain eq {}} return;
lassign [FindRootId $domain] RootId RootDomain; # ищем идентификатор правила, в чей домен входит домен из текущего правила
if {$RootId ne ""} { # обновляем атрибут в базе только если нашли Id родительского правила
sql "UPDATE Record SET RootRuleId=$RootId WHERE Id=$id;"; # обновляем атрибут RootRuleId в базе
puts [format {%7s | %25s | %7s | %s} $RootId $RootDomain $id $domain]
}
}
proc ballastRules::expandRule {id} {
set Domain [ExpandRuleInit $id]; # заполнить атрибуты RuleIsDomain и Domain
ExpandRuleRoot $id $Domain; # заполнить атрибут RootRuleId
}
proc ballastRules::expandAllRules {args} {
set qWHERE "RootRuleId=0 AND"
if {[lsearch $args "-force"] != -1} {set qWHERE ""}
set qListIdSelector "(SELECT Id FROM List WHERE TypeID = (SELECT Id FROM lst_ListTypes WHERE name='urls'))";
set sqlCmd "SELECT Id,Rule FROM Record WHERE ${qWHERE} ListId in $qListIdSelector;"
set sqlCmd "SELECT Id, Rule, Domain FROM Record WHERE ListId in $qListIdSelector AND ruleIsDomain=0 AND Domain != '';"
foreach {Id Rule Domain} [sql $sqlCmd] {
if {[ruleIsIp $Rule]} continue
ExpandRuleRoot $Id $Domain;
}
}
proc ballastRules::freeRootId {id} {
# после удаления правила, необходимо удалить его из указателей на него в атрибуте RootId в других правилах
sql "UPDATE Record SET RuleId=0 WHERE RuleId=$id;"
}
Такая система:
- обрабатывает только правила типа "*.urls";
- игнорирует правила, у которых не указано имя домена (правила типа "/banner.gif");
- фильтрует только правила с таким доменом, который входит в имя другого домена, для которого в базе есть точное правило Rule==Domain (если есть правила "ad.adriver.ru/cgi-bin", "content.adriver.ru/plugins/autoUpdate.adriver.js" и "https://www.adriver.ru/index.html", то они будут проигнорированы только в том случае, если в базе есть правило "adriver.ru", у которого строка правила является также и именем домена).