태깅은 정보를 관리하기 위한 좋은 방법이다. 완전히 공개된 서비스의 경우 태그관리가 까다롭다는 문제가 있지만, 추천시스템에 대한 노하우가 쌓이면서 많은 부분 해결이 된 것 같다.
Joinc는 개임위키이니 만큼 관리하기가 훨씬 쉽다. 태그라고 해봐야 100개가 넘지 않을 것 같은데, 이 정도라면 자동완성이나 추천에 신경쓰지 않고 단순하게 구성 할 수 있을 것이다. 자동완성쪽을 해보고 싶기는 한데, 이건 나중에 해볼 생각이다.
구성
태그 목록을 관리하는 테이블과 태깅 적용 정보를 가지는 두 개의 테이블로 구성된다.
관리자 계정으로 로그인하면, 태그를 관리 할 수 있다.
페이지 상단에 "현재 페이지 태깅" 메뉴가 추가된다.
태깅 관리 페이지로 넘어간다.
태깅 관리 페이지에는 사용 할 수 있는 태그 목록이 있다. 여기에서 태그를 선택한다.
아래와 같이 테이블을 만들었다.
CREATE TABLE joinctag (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(64) NOT NULL,
PRIMARY KEY(id)
);
CREATE TABLE wikitagging (
id INT NOT NULL AUTO_INCREMENT,
tagid INT NOT NULL,
pageid INT NOT NULL,
FOREIGN KEY (`tagid`) REFERENCES `joinctag`(`id`),
PRIMARY KEY(id)
)
화면 UI 구성
인터넷을 뒤져서 적당히 보기 좋은 녀석을 찾았다. Vue.js로 테스트를 했다. 그럭저럭 괜찮은 것 같다.
태그리스트에서 원하는 태그를 클릭하면, 페이지에 태그로 붙는다. 자동완성으로 하는게 더 편할 수 있겠는데 일단은 쉬운 방법으로 했다.
name 은 태그 이름이고 pageid는 태그된 페이지의 ID(유일한 식별번호)다.
aws 태그를 기준으로 보면, Aurora 태그가 2, bigdata 태그가 1임을 알 수 있다. 데이터의 일부이지만 여기에서 우리는 aws 태그와 연관있는 테이블을 선택하고 (얼마나 가까운지)가중치를 줄 수 있을 것이다. 단순 카운트일 경우 Aurora는 2의 가중치 bigdata는 1의 가중치를 가진다. 만드는 방법을 생각해보자.
태그 이름 목록은 별도의 테이블에 가지고 있다. 이 테이블을 순환하면서 각 태그의 연관 태그를 계산하면 된다. 예를 들어 "aws"에 대한 연관태그는 아래와 같이 만들 수 있을 것이다.
"aws"가 태깅된 문서의 목록 - pageid - 를 얻는다.
pageid에 태깅된 태그 이름을 가져온다.
해당 태그 이름에 카운트 한다.
그 결과 aws와 관련된 s3, go, msa 태그를 얻을 수 있으며, 가중치(얼마나 많은 관련성이 있는지)도 계산 할 수 있다.
위에 있는 이미지의 데이터를 가지고 테스트코드를 만들었다.
Contents
태깅
구성
- 관리자 계정으로 로그인하면, 태그를 관리 할 수 있다.
- 페이지 상단에 "현재 페이지 태깅" 메뉴가 추가된다.
- 태깅 관리 페이지로 넘어간다. 
- 태깅 관리 페이지에는 사용 할 수 있는 태그 목록이 있다. 여기에서 태그를 선택한다.
아래와 같이 테이블을 만들었다.CREATE TABLE joinctag ( id INT NOT NULL AUTO_INCREMENT, name VARCHAR(64) NOT NULL, PRIMARY KEY(id) ); CREATE TABLE wikitagging ( id INT NOT NULL AUTO_INCREMENT, tagid INT NOT NULL, pageid INT NOT NULL, FOREIGN KEY (`tagid`) REFERENCES `joinctag`(`id`), PRIMARY KEY(id) )화면 UI 구성
<div class="row"> <div class="large-12 column"> <div id="app"> <pagetag-management></pagetag-management> </div> </div> </div> <script> Vue.component('pagetag-management', { template: ` <div class="row"> <div class="large-12 columns"> <div class="tag-cloud"> <ul class="stats-list"> <li class="vlist" v-for="(item, key) in tags"> <a class="tag-cloud-individual-tag" href="javascript: void(0)" v-on:click="removeTagging(key)">{{ item }} <i class="fa fi-minus" aria-hidden="true"></i> </a> </li> </ul> </div> </div> <div class="large-12 columns"> <hr> </div> <div class="large-12 columns"> <div class="tag-cloud"> <ul class="stats-list"> <li class="vlist" v-for="(item, key) in items"> <a class="tag-cloud-individual-tag" href="javascript: void(0)" v-on:click="addTagging(key)">{{ item }} <i class="fa fi-plus" aria-hidden="true"></i> </a> </li> </ul> </div> </div> </div>`, data: function() { return { name: [], items: ["api-gateway","Aurora","aws","beanstalk","bigdata","blog","cache","cli","cloudwatch","configuration","database","devops","distribute","docker","ec2","ecs","ELB","encrypt","geohash","golang","hadoop","hash","html5","iam","javascript","joinc","json","Kafka","lambda","logging","messaging","msa","mysql","network","nginx","nosql","package","proxy","redis","rpc","s3","spatial","tag","test","tip","tutorial","vpc","vue.js","미완성","분산시스템"], tags: [] } }, methods: { addTagging: function(index) { this.tags.push(this.items[index]) this.items.splice(index, 1) }, removeTagging: function(index) { this.items.push(this.tags[index]) this.tags.splice(index, 1) }, } }); new Vue({ el: '#app' }); </script>methods: { addTagging: function(index) { axios.post('/api/addtag', {id: 4, name: this.items[index] }, {headers: { 'Content-type': 'application/json', }}).then(response => { if (response.status == 200) { this.tags.push(this.items[index]) this.items.splice(index, 1) } }); }, removeTagging: function(index) { axios.post('/api/removetag', {id: 4, name: this.tags[index] }, {headers: { 'Content-type': 'application/json', }}).then(response => { if (response.status == 200) { this.items.push(this.tags[index]) this.tags.splice(index, 1) } }); }, }태그 클라우드 만들기
Tags
<div class="row"> <div class="large-12 column"> <div id="app_tagcount"> <tagcount-list></tagcount-list> </div> </div> </div> <script> Vue.component('tagcount-list', { delimiters: ["<%","%>"], template:` <div class="tag-list"> <ul class="tag-ul"> <li class="vlist" v-for="(item, key) in items"> <a class="tag-cloud-individual-tag" v-bind:href="'https://www.joinc.co.kr/w/taglist?name='+ item.Name"><% item.Name %> ··· <% item.Num %></a> </li> </ul> </div>`, data: function() { return { items: [{"Name":"aws","Num":18},{"Name":"javascript","Num":8}] } } }) new Vue({ el:"#app_tagcount" }) </script>관련 태그 만들기
- "aws"가 태깅된 문서의 목록 - pageid - 를 얻는다.
- pageid에 태깅된 태그 이름을 가져온다. 
- 해당 태그 이름에 카운트 한다. 
그 결과 aws와 관련된 s3, go, msa 태그를 얻을 수 있으며, 가중치(얼마나 많은 관련성이 있는지)도 계산 할 수 있다. 위에 있는 이미지의 데이터를 가지고 테스트코드를 만들었다.package main import ( "fmt" ) type tags struct { pageid int name []string } func getRelateTag(tagName string, testItem []tags) map[string]int { pageIds := []int{} for _, v := range testItem { for _, name := range v.name { if name == tagName { pageIds = append(pageIds, v.pageid) } } } relateTag := make(map[string]int) for _, pid := range pageIds { for _, name := range testItem[pid].name { if name == tagName { continue } if _, ok := relateTag[name]; ok { relateTag[name]++ } else { relateTag[name] = 1 } } } return relateTag } func main() { tagList := []string{"aws", "s3", "go", "rds", "msa"} testItem := []tags{ {0, []string{}}, {1, []string{"aws", "s3", "go"}}, {2, []string{"s3", "rds"}}, {3, []string{"aws", "s3"}}, {4, []string{"aws", "s3", "msa"}}, {5, []string{"msa"}}, {6, []string{"s3", "go"}}, } for _, name := range tagList { fmt.Println(name, " : ", getRelateTag(name, testItem)) } }태그 그래프 만들기
인기태그
- 태그 카운트 : 당연히 카운트가 높은 태그가 인기태그일 것이다.
- 시간 : 시간이 지날 수록 태그 인기도는 떨어져야 한다.
적당한 튜닝이 필요하겠으나 태그 카운트 * 시간 = 인기도로 계산 할 수 있을 것이다.유저별 태그 추천
{"user":"yundream", "tag":["aws","s3"], "pageid":3710, "time":"2018-06-29T09:43:58Z"} {"user":"kong", "tag":["aws","msa"], "pageid":3122, "time":"2018-06-29T09:52:58Z"} {"user":"yundream", "tag":["aws","rds"], "pageid":1503, "time":"2018-06-29T09:52:58Z"} {"user":"yundream", "tag":["s3","go", "rds"], "pageid":2200, "time":"2018-06-29T10:10:58Z"} {"user":"kong", "tag":["s3","rds"], "pageid":1119, "time":"2018-06-29T09:52:58Z"} {"user":"yundream", "tag":["aws","msa"], "pageid":3082, "time":"2018-06-29T10:10:58Z"} {"user":"yundream", "tag":["go"], "pageid":3317, "time":"2018-06-29T10:10:58Z"}Recent Posts
Archive Posts
Tags