Словарь / дерево быстрого поиска на основе поиска

У меня есть база данных из 20000 доменных имен, включая домены верхнего уровня, домены второго и нижнего уровня. Например

.biz stackru.com ru.wikipedia.com

Я хотел бы выполнить быстрый поиск, чтобы увидеть, соответствуют ли входные URL-адреса любому из этих 20000. Я мог бы использовать ключ словаря или HashSet.Contains, но он подходит только для точных совпадений. Поскольку база данных также содержит имена доменов верхнего уровня, я бы хотел, чтобы файл acmeycompany.biz также возвращался как совпадающий из-за домена верхнего уровня.biz. С другой стороны, fr.wikipedia.com не должен совпадать, поскольку поддомен отличается.

Простой цикл по списку и сравнение на основе строк также не вариант. Если у меня есть 1000 URL для сравнения, это просто слишком медленно. Так что это должен быть поиск по индексу на основе ключа.

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

.com.wikipedia.ru.stackru.biz

Затем я могу разделить входной URL-адрес (sampledomain.com) на части и выполнить поиск следующим образом.com -> .sampledomain

Кто-нибудь может указать мне образец, как это сделать? Или каковы другие альтернативы? Любые образцы приветствуются.

Спасибо!

Вот как я начал... Это код vb.net, но вы поняли идею.

 Public Class TreeNode

    Sub New()
        ChildNodes = New Dictionary(Of String, TreeNode)
    End Sub

    Public Property Key As String
    Public Property ChildNodes As Dictionary(Of String, TreeNode)

End Class

Private Tree As New Dictionary(Of String, TreeNode)

Sub BuildTree()

    For Each Link In Links

        If Uri.IsWellFormedUriString(Link, UriKind.Absolute) Then

            Dim Url As New Uri(Link)
            Dim Domain As String

            If Url.HostNameType = UriHostNameType.Dns Then

                Domain = Url.Host.ToLower.Replace("www.", "")

                Dim DomainParts() As String = Domain.Split(CChar("."))

                'lets start from TLD
                For Each Key In DomainParts.Reverse

                    'dont konw how to populate tree

                Next

            End If

        End If

    Next

End Sub

Function TreeLookup(Link As String) As Boolean

    Dim Url As New Uri(Link)
    Dim Domain As String
    Dim IsMatch As Boolean = False

    If Url.HostNameType = UriHostNameType.Dns Then

        Domain = Url.Host.ToLower.Replace("www.", "")

        Dim DomainParts() As String = Domain.Split(CChar("."))
        Dim DomainPartsCount As Integer = DomainParts.Length
        Dim Index As Integer = 0


        For Each Key In DomainParts

            Index += 1

            'use recursive loop to see if 

            'returns true if directory contains key and we have reached to the last part of the domain name
            If Index = DomainPartsCount Then

                IsMatch = True
                Exit For

            End If

        Next

    End If

    Return IsMatch

End Function

2 ответа

Вы можете создать словарь словарей хэш-карт. Первый словарь может содержать все записи ДВУ в паре со словарем всех доменов второго уровня, имеющих этот ДВУ. Тогда каждый домен второго уровня может содержать хэш-карту всех доменов нижнего уровня, которые он содержит. У каждой записи также будет флаг, указывающий, действительно ли эта запись находится в базе данных или просто заполнитель для записей более низкого уровня. Как и в коротком списке, который вы использовали, .com на самом деле отсутствует в списке, но все равно будет записью в ДВУ, поэтому предоставьте доступ к stackru.com а также wikipedia.com (который сам по себе будет заполнителем для ru.wikipedia.com). Затем поиск будет начинаться с TLD URL-адресов, затем со второго и, наконец, более низкого уровня, если необходимо углубиться.

Надеюсь, я правильно понял вашу дилемму и адекватно объяснил свою идею.

Редактировать: самый низкий уровень должен быть только хэш-картой.


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

Чтобы добавить домен, вы можете сделать что-то вроде этого (это можно сделать рекурсивным, если хотите, но только с тремя уровнями это не имеет большого значения):

// TLD, SLD and LLD are the three levels of the current domain you are adding into the tree
if Tree does not contain the TLD
    Add TLD to the Tree with a new TreeNode

if SLD does not exist for the current domain
    Mark the Tree at TLD as a match
else   
    if Tree[TLD] does not contain the SLD
        Add SLD to the Tree[TLD] Node

    if LLD does not exist for the current domain
        Mark the Tree[TLD] at SLD as a match
    else   
        if Tree[TLD][SLD] does not contain the LLD
            Add LLD to the Tree[TLD][SLD] Node
            // Don't really need to mark the node
            // as every LLD would be a match
            // Probably would need to mark if made recursive

Чтобы найти домен (опять же, можно сделать рекурсивным):

// TLD, SLD and LLD are for the domain you looking for
if Tree does not contain TLD
    you are done, no match
else
    if Tree[TLD] is marked
        done, match
    else
        if Tree[TLD] does not contain SLD
            done, no match
        else
            if Tree[TLD][SLD] is marked
                done, match
            else
                if Tree[TLD][SLD] contains LLD
                    done, match
                    // would need to check if the node
                    // is marked if made recursive

Когда вы храните элементы в своей базе данных, у каждой части URL должен быть свой столбец. Таким образом, TLD, домен и поддомен будут представлять собой свои собственные столбцы.

create table MyList
(
    [TLD] nvarchar(10) not null,
    [Domain] nvarchar(50) not null,
    [Subdomain] nvarchar(50) not null,

    unique ([TLD], [Domain], [Subdomain]) 
    --this means that you can't add the same data twice
)

Теперь используйте SQL, чтобы получить нужные данные.

select *
from MyList
where [TDL] = '.com'

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

Что касается причины для таблицы, прочитайте о нормализации базы данных

Вам нужно будет выполнить какое-то преобразование данных, если вы храните свои URL-адреса только в одном столбце.

Другие вопросы по тегам