2015-04-17 50 views
0

我在我的SQLite數據庫中有一列10k個URI。我想確定哪些URI是同一網站的子域名。在SQL列中查找類似條目並按頻率排列

例如,對於給定的一組...

1. daiquiri.rum.cu 
2. mojito.rum.cu 
3. cubalibre.rum.cu 
4. americano.campari.it 
5. negroni.campari.it 
6. hemingway.com 

...我想運行一個返回查詢:

Website  | Occurrences 
---------------------------- 
rum.cu  |  3 
campari.it |  2 
hemingway.com |  1 

也就是說,域名/模式,被匹配,按數據庫中發現的次數排名。

我將使用的啓發式是:對於具有3個以上域的每個URI,用'%'替換第一個域並執行僞查詢:COUNT(來自網站的uris,其中uris LIKE'%.remainderofmyuri')。

請注意,我並不在乎執行速度(事實上根本不在乎)。條目數在10k-100k的範圍內。

+0

rum.com從哪裏來?這是rum.cu的錯字嗎? (或者反過來。) –

+0

是的!感謝您的評論。 – bsuire

回答

1

唯一的問題是找到域。爲了找到一個算法想象你的網站前面有一個額外的點(如'.negroni.campari.it'和'.hemingway.com')。你會發現它總是來自右側第二個點之後的字符串。我們所要做的就是查找該事件並剝離字符串的一部分。不幸的是,SQLite的字符串函數相當差。沒有函數可以讓你第二次出現點,即使從左邊開始計算。所以對大多數dbms來說,算法很好,但它不適用於SQLite。我們需要另一種方法。 (我寫這無論如何,以顯示如何通常接近這個問題。)

這是SQLite解決方案:域和子域的區別是,在域中有一個點,而一個子域有至少兩個。所以當有多個點時,我們必須刪除包含第一個點的第一個部分才能到達域。此外,我們希望這個功能即使對於像abc.def.geh.ijk.com這樣的子域來說也是如此,所以我們必須遞歸地做到這一點。

with recursive cte(uri) as 
(
    select uri from uris 
    union all 
    select substr(uri, instr(uri, '.') + 1) as uri from cte where instr(uri, '.') > 0 
) 
select uri, count(*) 
from cte 
where length(uri) = length(replace(uri,'.','')) + 1 -- domains only 
group by uri 
order by count(*) desc; 

在這裏,我們產生「daiquiri.rum.cu」和「daiquiri.rum.cu」等「rum.cu」和「銅」因此,對於每一個URI,我們得到的域(這裏的朗姆酒。 cu')和其他一些字符串。最後我們用LENGTH過濾得到那些有一個點的字符串 - 域。剩下的就是一羣一羣的人。

這裏是SQL小提琴:http://sqlfiddle.com/#!5/c1f35/37

+0

謝謝,這有很大幫助!這絕對是正確的答案,基於我如何提出了這個問題,我應該指出我只是想確定第一個子域(如我的示例數據),但是我能夠從中找出它,謝謝! – bsuire

0
select x.site, count(*) 
from mytable a 
inner join 
(
    select 'rum.cu' as site 
    union all select 'campari.it' 
    union all select 'hemingway.com' 
) x on a.url like '%' + x.site + '%' 
group by x.site -- EDIT I missed out the GROUP BY on the first go - sorry! 

(這是我怎麼會做它的SQL服務器;不知道的SQLite在語法上的區別。)

「MYTABLE」是你的表whuch有一個名爲包含「莫吉托網址列。 rum.cu'等。我沒有把'%'。因爲那樣會錯過hemmingway.com。然而,你可以得到解決,通過使用該行:

) x on a.url like '%.' + x.site + '%' or a.url = x.site 

您可能不需要fimal +「%」 - 我把它趕上像「hemingway.com/some-page.html網址。如果你沒有這樣的網址,你可以跳過。

編輯動態名

select x.site, count(*) 
from mytable a 
inner join 
(
    select distinct ltrim(url, instr(url, '.')) as site 
    from mytable 
    where url like '%.%.%' 
    union 
    select distinct url 
    from mytable 
    where url like '%.%' and url not like '%.%.%' 
) x on a.url like '%' + x.site + '%' 
group by x.site 

類似的東西應該這樣做。我沒有測試過INSTR()函數是否正確。您可能需要在測試它時生成的偏移量中加上或減去1。它可能不是最快的查詢,但它應該工作。

+0

謝謝!是否有可能修改查詢以使domai名稱是動態的?在實際應用中,我不知道哪些域具有子域。 – bsuire

+0

您是否有任何帶有網頁的網址,例如: hemmingway.com/somepage.html? –

+0

不,路徑已被全部截斷。 – bsuire