Код: Выделить всё
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", у которого строка правила является также и именем домена).