1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package main
 
import (
    "bytes"
    "errors"
    "fmt"
    "math/rand"
    "net"
    "time"
 
    "github.com/geeksbaek/goinside"
    "github.com/xrash/smetrics"
)
 
type Gallery struct {
    url string
}
 
type Article struct {
    subject string
    date    time.Time
    ip      net.IP
}
 
type Articles []*Article
 
const (
    maxDupSubjectCnt = 1
    maxDupIPAddrCnt  = 5
    comparePageCnt   = 10
)
 
func main() {
    start := time.Now()
 
    err := writeArticle(&Article{
        subject: "제목",
        date:    time.Now(),
        ip:      _randIP(),
    }, &Gallery{
        url: "http://gall.dcinside.com/board/lists/?id=programming",
    })
 
    fmt.Println("validate duration :", time.Since(start))
    fmt.Println("Error:", err)
}
 
func writeArticle(newArticle *Article, gall *Gallery) error {
    dupSubjectCnt, dupIPAddrCnt := 00
    for _, oldArticle := range readRecentlyArticles(gall) {
        if !isNearTime(newArticle, oldArticle) {
            continue
        }
        switch {
        case isDupSubject(newArticle, oldArticle):
            dupSubjectCnt++
        case isDupIP(newArticle, oldArticle):
            dupIPAddrCnt++
        }
    }
 
    switch {
    case maxDupSubjectCnt <= dupSubjectCnt:
        return errors.New("Over Maximum Subject Limit")
    case maxDupIPAddrCnt <= dupIPAddrCnt:
        return errors.New("Over Maximum IP Address Limit")
    }
    // doWrite(a)
    return nil
}
 
func readRecentlyArticles(gall *Gallery) (as Articles) {
    start := time.Now()
    for i := 1; i < comparePageCnt; i++ {
        list, err := goinside.GetList(gall.url, i)
        if err != nil {
            continue
        }
        for _, article := range list.Articles {
            as = append(as, &Article{
                subject: article.Subject,
                date:    *article.Date,
                ip:      _randIP(),
            })
        }
    }
    fmt.Println("recently article length :", len(as))
    fmt.Println("fetch duration :", time.Since(start))
    return
}
 
func isDupSubject(a, b *Article) bool {
    if smetrics.JaroWinkler(a.subject, b.subject, 0.74> 0.9 {
        return true
    }
    return false
}
 
func isNearTime(a, b *Article) bool {
    format := "2006/01/02 15:04"
    if a.date.Format(format) == b.date.Format(format) {
        return true
    }
    return false
}
 
func isDupIP(a, b *Article) bool {
    if bytes.Equal(a.ip, b.ip) {
        return true
    }
    return false
}
 
func _randIP() net.IP {
    rand.Seed(time.Now().UnixNano())
    ipStr := fmt.Sprintf("%v.%v.%v.%v", rand.Intn(255), rand.Intn(255), rand.Intn(255), rand.Intn(255))
    return net.IP(ipStr)
}
 
cs


비교 대상은 글이 작성되는 게시판의 최근 글 10페이지


1. 분단위 동일한 시간에 글 제목에 대해 Jaro Winkler 알고리즘으로 90% 이상의 매칭도를 가지는 글이 1개 이상 있는 경우

2. 분단위 동일한 시간에 동일한 아이피가 5개 이상 있는 경우


너네가 게시판 운영자라면 어떤 알고리즘으로 필터링하고싶냐