본문 바로가기
python 및 머신러닝/집단지성 프로그래밍

[Programming Collective Intelligence] - 집단지성 프로그래밍 4장 검색과 랭킹

by java개발자 2015. 8. 31.
# -*- coding: utf-8 -*-
from myutil import consolePrintWithLineNumber as c
'''
Created on 2015. 8. 31.

@author: Administrator
'''

'''
  4장 검색과 랭킹
'''

# 86p 02절 단순 크롤러

'''
  파이썬3.4에서는 urllib2가 설치가 안된다.
  > pip install urllib3
  참고 : https://urllib3.readthedocs.org/en/latest/
  
  파이썬3.4에서는 BeautifulSoup가 설치가 안된다.??
  > pip install BeautifulSoup4 
  참고 :http://www.crummy.com/software/BeautifulSoup/
  
  sqlite3는 파이썬3에서 기본으로 제공
  단, 책의 소스와 일부 다르다.
    # Never do this -- insecure!
    symbol = 'RHAT'
    c.execute("SELECT * FROM stocks WHERE symbol = '%s'" % symbol)
    
    # Do this instead
    t = ('RHAT',)
    c.execute('SELECT * FROM stocks WHERE symbol=?', t)
    print c.fetchone()
    
    # Larger example that inserts many records at a time
    purchases = [('2006-03-28', 'BUY', 'IBM', 1000, 45.00),
                 ('2006-04-05', 'BUY', 'MSFT', 1000, 72.00),
                 ('2006-04-06', 'SELL', 'IBM', 500, 53.00),
                ]
    c.executemany('INSERT INTO stocks VALUES (?,?,?,?,?)', purchases)

  참고 : https://docs.python.org/3/library/sqlite3.html
  
  새롭게 사용된 방법
    except 에서 메시지 보기 : sys.exc_info()[0]
    스트링 포맷 지정 : "STRING {0}, {1}".format('A','B')
      
      
    [crawl 순서]
    1.url 접속 및 HTML 크롤링
    2.url 에 대한 인덱스 생성
      1.기존 url 인덱스 존재 여부 확인
      2.HTML Text를 단어로 파싱
      3.url 등록 (urllist테이블)
      4.단어 등록 (wordlist테이블)
      5.url-단어 등록 (wordlocation테이블)
    3.HTML내의 a링크 찾기
      1.새로운 url인 경우
        1.url 등록 (urllist 테이블)
        2.링크 등록(link 테이블)
        3.a링크의 텍스트를 단어로 파싱
          1.단어 등록 (wordlist 테이블)
          2.단어 등록 (linkwords 테이블)

  테이블 설명
    기본으로 내장된 rowid 필드(물리적 필드 아님)를 PK로 활용하는 테이블 : urllist, wordlist, link
    urllist(url)
    wordlist(word)
    wordlocation(urlid,wordid,location)
    link(fromid,toid)
    linkwords(wordid,linkid)
  
  크롤링 테스트 방법
    테스트 페이지로 연결되어있는 테스트페이지들을 localhost:8080 서버에 포팅 후 접속
    localhost.db를 이용
'''
import urllib3
import io
def practice0():
  http = urllib3.PoolManager()
  r = http.request('GET', 'http://naver.com')
  c(r.status)
  c(r.headers['server'])
  c(r.data.decode('utf-8'))
  # b = io.BufferedReader(r, 2048)
  # firstpart = b.read(2048)
  # c(firstpart)
  r.closed
# practice0()

from bs4 import BeautifulSoup
from urllib.parse import urljoin
import sqlite3 as sqlite    # 파이썬3에서 기본으로 제공
import sys
import re
  
ignorewords = set(['the', 'of', 'to', 'and', 'a', 'in', 'is', 'it'])

# 85p 정의하고, 책 뒷부분에서 하나하나 소스를 채워나감..
class crawler:
  def __init__(self, dbname):
    self.con = sqlite.connect(dbname)
    self.cur = self.con.cursor()
  def __del__(self):
    self.con.close()
  def dbcommit(self):
    self.con.commit()
  # 해당 테이블의 컬럼에서 데이터를 조회해서 없으면, 새로 추가하고, id를 리턴한다
  def getentryid(self, table, field, value, createnew=True):
    sql = "SELECT rowid FROM {0} WHERE {1} = \'{2}\'".format(table, field, value)
    self.cur.execute(sql)
    res = self.cur.fetchone()
    if res == None:
      sql = "insert into {0} ({1}) values (\'{2}\')".format(table, field, value)
      self.cur.execute(sql)
      return self.cur.lastrowid
    else:
      return res[0] 
  # 개별 페이지 색인
  def addtoindex(self, url, soup):
    if self.isindexed(url): return
    c('Indexing ' + url)
  
    text = self.gettextonly(soup)
    words = self.separatewords(text)
    
    urlid = self.getentryid('urllist', 'url', url)
    
    for i in range(len(words)):
      word = words[i]
      if word in ignorewords: continue
      wordid = self.getentryid('wordlist', 'word', word)
      self.cur.execute("insert into wordlocation(urlid, wordid, location) values (?,?,?)" , (urlid, wordid, i,))
  # HTML 에서 텍스트 추출
  def gettextonly(self, soup):
    v = soup.string
    if v == None:   
      c = soup.contents
      resulttext = ''
      for t in c:
        subtext = self.gettextonly(t)    # 재귀
        resulttext += subtext + '\n'
      return resulttext
    else:
      return v.strip()
  def separatewords(self, text):
    splitter = re.compile('\\W*')    # 알파벳이 아닌 문자로 나누기
    return [s.lower() for s in splitter.split(text) if s != '']
  # 색인 되었나?(True)
  def isindexed(self, url):
    self.cur.execute("SELECT rowid FROM urllist WHERE url=?", (url,))
    u = self.cur.fetchone()
    if u != None:
      self.cur.execute("SELECT * FROM wordlocation WHERE urlid = ?", (u[0],))
      v = self.cur.fetchone()
      if v != None:
        c('this url \'%s\' is already indexed.' % (url))
        return True    # 해당 url이 urllist테이블에 있어야 하고, wordlocation테이블에 단어들이 있어야 인덱싱이 되었다고 볼 수 있다.
    return False
  # 두 페이지 간의 링크 추가(책에 내용이 없다. 첨부소스로 확인)
  def addlinkref(self, urlFrom, urlTo, linkText):
    words = self.separatewords(linkText)
    fromid = self.getentryid('urllist', 'url', urlFrom)
    toid = self.getentryid('urllist', 'url', urlTo)
    if fromid == toid: return
    
    # 책 소스대로 할 경우 재실행 했을때 중복으로 입력되는 경우가 발생한다. 중복검사해서 return 처리필요
    sql = "SELECT rowid FROM link WHERE fromid = \'{0}\' and toid = \'{1}\'".format(fromid, toid)
    self.cur.execute(sql)
    res = self.cur.fetchone()
    if res != None: return
    # 수정 end
    
    self.cur.execute("insert into link(fromid,toid) values (?,?)", (fromid, toid,))
    linkid = self.cur.lastrowid
    for word in words:
      if word in ignorewords: continue
      wordid = self.getentryid('wordlist', 'word', word)
      self.cur.execute("insert into linkwords(linkid,wordid) values (?,?)", (linkid, wordid,))
  # 넓이 우선 검색으로
  def crawl(self, pages, depth=2):
    c('start crawling')
    for i in range(depth):
      newpages = {}
      for page in pages:
        try:
          http = urllib3.PoolManager()
          r = http.request('GET', page)
        except:
          c("Could not open %s" % page)
          r.closed
          continue
        try:
          soup = BeautifulSoup(r.data.decode('utf-8'))
          r.closed
          self.addtoindex(page, soup)
          
          links = soup('a')
          for link in links:
            if ('href' in dict(link.attrs)):
              url = urljoin(page, link['href'])    # href가 상대주소이면, page와 함해서 절대주소로 만들어준다.
              if url.find("'") != -1: continue
              url = url.split('#')[0]    # html 태그 속성중 id로 focus된 부분을 삭제
              # depth를 2로 실행한 후, 3으로 다시 실행하면, 2까지는 모두 인덱싱이 처리되었기 때문에 3으로 진행하기 전에 처리가 종료된다. 계속 진행하기 위해 소스 수정
              # if url[0:4] == 'http' and not self.isindexed(url):
              if url[0:4] == 'http':    # and not self.isindexed(url):  #소스 수정
                newpages[url] = 1
              linkText = self.gettextonly(link)
              self.addlinkref(page, url, linkText)
  
          self.dbcommit()
        except:
          c("Could not parse page %s" % page)
          c("Unexpected error:", sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])

      pages = newpages    
      
  # 데이터베이스 테이블 생성(1회)
  def createindextables(self):
    # 테이블을 삭제하고, 다시 생성
    self.con.execute('drop table if exists urllist') 
    self.con.execute('drop table if exists wordlist') 
    self.con.execute('drop table if exists wordlocation') 
    self.con.execute('drop table if exists link') 
    self.con.execute('drop table if exists linkwords')
     
    self.cur.execute('create table urllist(url)')
    self.cur.execute('create table wordlist(word)')
    self.cur.execute('create table wordlocation(urlid,wordid,location)')
    self.cur.execute('create table link(fromid integer,toid integer)')
    self.cur.execute('create table linkwords(wordid,linkid)')
    
    self.cur.execute('create index wordidx on wordlist(word)')
    self.cur.execute('create index urlidx on urllist(url)')
    self.cur.execute('create index wordurlidx on wordlocation(wordid)')
    self.cur.execute('create index urltoidx on link(toid)')
    self.cur.execute('create index urlfromidx on link(fromid)')
    self.dbcommit()
    c('create finished.')
    
  # 테이블 데이터 삭제
  def deleteAlldatas(self):
    self.cur.execute('delete from urllist')
    self.cur.execute('delete from wordlist')
    self.cur.execute('delete from wordlocation')
    self.cur.execute('delete from link')
    self.cur.execute('delete from linkwords')
    self.dbcommit()
    c('delete finished.')
  
  # 06절 페이지랭크 만들기 - pagerank 테이블에 저장
  def calculatepagerank(self, iterations=20):
    self.con.execute('drop table if exists pagerank')
    self.con.execute('create table pagerank(urlid primary key,score)')
    
    # db 조회필드가 두개인 경우 결과 값으로 (1,2,) 처럼 뒤에 콤마가 붙은 튜플로 나온다. 튜플이 아닌, 값으로 빼내기 위해 (urlid,) 처럼 기술한다. (urlid)로 적어도 된다.
    for (urlid,) in self.con.execute('select rowid from urllist'):
      self.con.execute('insert into pagerank(urlid,score) values (%d, 1.0)' % urlid)
    self.dbcommit()
    
    '''
      페이지랭크 점수 계산법
      0.15 + 0.85 * sum(1페이지의 페이지랭크점수 / 1페이지안의 링크 개수, 2페이지의 페이지랭크점수 / 2페이지안의 링크 개수,,,,)
    '''
    # 적절한 iterations 값은 얼마일까? 일정 카운트 이상에서는 데이터가 어느점으로 수렴해가는 것을 눈으로 보면 좋을 듯 하다. 그래프로??? 
    for i in range(iterations):
      c("Iteration %d" % i)
      for (urlid,) in self.con.execute('select rowid from urllist'):
        pr = 0.15
        
        for (fromid,) in self.con.execute('select distinct fromid from link where toid=%d' % urlid):

          pagerankscore = self.con.execute('select score from pagerank where urlid=%d' % fromid).fetchone()[0]
          linktotalcount = self.con.execute('select count(*) from link where fromid=%d' % fromid).fetchone()[0]
            
          pr += 0.85 * (pagerankscore / linktotalcount)
        self.con.execute('update pagerank set score=%f where urlid=%d' % (pr, urlid))
#         c(i, urlid, pr)
      self.dbcommit() 
##########################################################################################

# 88p 테스트
def practice1():
  cr = crawler('')    # db 없이 테스트할때... 소스가 변경된 이후에는 테스트 불가
  cr.crawl(['http://naver.com'])
# practice1()

# 89p 03절 색인하기
# 1회 실행(테이블 생성)
# crawler('searchindex.db').createindextables()

# 93p 크롤러 실행
def practice2():
  crawler('searchindex.db').createindextables()
  cr = crawler('searchindex.db')
  cr.crawl(['http://www.naver.com'], depth=3)
# practice2()

# 94p DB 확인
def practice3():
  practice2()
  
  cr = crawler('searchindex.db')
  cr.cur.execute('select rowid from wordlocation where wordid=3')
  c(cr.cur.fetchall())
# practice3()

# 임시 페이지로 크롤러 실행하기 - DB에 데이터 쌓기
def practice4():
  # 테이블 삭제하고, 다시 생성.
  crawler('localhost.db').createindextables()
  
  cr = crawler('localhost.db')
  # cr.crawl(['http://192.168.1.15:8080/start.html'], depth=2)
  cr.crawl(['http://192.168.1.15:8080/start.html'], depth=3)    # 같은 주소로 depth를 넓힐 경우 db에 중복입력되는 경우 발생(addlinkref 함수 부분 수정함) 
# practice4()

############################################################################################

# 94p 04절 검색하기
class searcher:
  def __init__(self, dbname):
    self.con = sqlite.connect(dbname)
    self.cur = self.con.cursor()
  def __del__(self):
    self.con.close()
  def getmatchrows(self, q):
    fieldlist = 'w0.urlid'
    tablelist = ''  
    clauselist = ''
    wordids = []
    
    words = q.split(' ')
    tablenumber = 0
    
    # dynamic sql 만들기
    for word in words:
      wordrow = self.con.execute("select rowid from wordlist where word='%s'" % word).fetchone()
      if wordrow != None:
        wordid = wordrow[0]
        wordids.append(wordid)
        if tablenumber > 0:
          tablelist += ','
          clauselist += ' and '
          clauselist += 'w%d.urlid=w%d.urlid and ' % (tablenumber - 1, tablenumber)
        fieldlist += ',w%d.location' % tablenumber
        tablelist += 'wordlocation w%d' % tablenumber      
        clauselist += 'w%d.wordid=%d' % (tablenumber, wordid)
        tablenumber += 1
    
    fullquery = 'select %s from %s where %s' % (fieldlist, tablelist, clauselist)
    
    # 오류 방지 소스 추가
    if clauselist == '':
      c("this words '%s' is not included" % words)
      return None    # where절이 만들어지지 않은 쿼리는 처리 하지 않음.
    # 소스 추가 end
    
    c(fullquery)
    self.cur.execute(fullquery)
    rows = [row for row in self.cur.fetchall()]
    
    return rows, wordids
  
  # 05절 내용 기반 랭킹에서 추가됨
  def getscoredlist(self, rows, wordids):
    totalscores = dict([(row[0], 0) for row in rows])
    '''
      {1: 0, 2: 0, 3: 0}
      urlid 1번은 0점
      urlid 2번은 0점
      urlid 3번은 0점...
    '''
    
      # 가중치 - 각 점수들에 가중치를 부여하기 (득점함수)
#     weights = []
    
#     weights = [(1.0, self.frequencyscore(rows))]
#     c(weights)    # [(1.0, {1: 0.5, 2: 1.0, 3: 1.0})]
    
#     weights = [(1.0, self.locationscore(rows))]

#     weights = [(1.0, self.distancescore(rows))]
    
#     weights = [(1.0, self.inboundlinkscore(rows))]
#     c(weights)

#     weights = [(1.0, self.locationscore(rows)),
#              (1.0, self.frequencyscore(rows)),
#              (1.0, self.pagerankscore(rows))]
    
#     weights = [(1.0, self.locationscore(rows)),
#              (1.0, self.frequencyscore(rows)),
#              (1.0, self.pagerankscore(rows)),
#              (1.0, self.linktextscore(rows, wordids))]
#     c(weights)
        
    weights = [(1.0, self.locationscore(rows)),
             (1.0, self.frequencyscore(rows)),
             (1.0, self.pagerankscore(rows)),
             (1.0, self.linktextscore(rows, wordids)),
             (5.0, self.nnscore(rows, wordids))]

    # 가중치 결과들을 합산하기
    for (weight, scores) in weights:
      for urlid in totalscores:
        totalscores[urlid] += weight * scores[urlid]

    return totalscores
  def geturlname(self, urlid):
    self.cur.execute("select url from urllist where rowid=?", (urlid,))
    return self.cur.fetchone()[0]

  def query(self, q):
    rows, wordids = self.getmatchrows(q)
    # 결과가 없는 경우 에러 방지
    if len(rows) == 0:
      return None
    '''
      rows, wordids : 
      ([(1, 5, 1), (1, 7, 1), (3, 5, 1), (3, 7, 1), (3, 9, 1), (3, 11, 1), (2, 5, 1), (2, 7, 1), (2, 9, 1), (2, 11, 1)], [6, 2])
      rows :
        [(urlid, location of word1, location of word2,,,,),,,]
    '''
    scores = self.getscoredlist(rows, wordids)
    c(scores)    # {1: 0.5, 2: 1.0, 3: 1.0}

    rankedscores = [(score, urlid) for (urlid, score) in scores.items()]    # key와  value를 뒤바꾸기 - 훌륭하다^^.
    rankedscores.sort()
    rankedscores.reverse()
    for (score, urlid) in rankedscores[0:10]:
      print('%f\t%s' % (score, self.geturlname(urlid)))
    return wordids, [urlid for (score, urlid) in rankedscores[0:10]]
  
  # 점수를 골고루 보편화 하기(정규화)...(0 <= x <= 1)
  def normalizescores(self, scores, smallIsBetter=0):
    vsmall = 0.00001
    if smallIsBetter != 0:    #   if smallIsBetter: 과 같다.
      minscore = min(scores.values())
      return dict([(u, float(minscore) / max(vsmall, l)) for (u, l) in scores.items()])    # 분자는 고정이고, 분모가 바뀌므로 작은것이 큰 값이 된다.
    else:
      maxscore = max(scores.values())
      if maxscore == 0:
          maxscore = vsmall
      return dict([(u, float(c) / maxscore) for (u, c) in scores.items()])

  # 가중치 함수1(득점함수)
  def frequencyscore(self, rows):
    counts = dict([(row[0], 0) for row in rows])
    for row in rows:
      counts[row[0]] += 1
    c(counts)
    '''
        해당 단어들이 각 페이지에서 몇번 노출되었는지 합계
      counts : {1: 2, 2: 4, 3: 4}
    '''
    return self.normalizescores(counts)    
  
  # 가중치 함수2(득점함수)
  # 각 단어가 해단 문서에서 몇번째 있었는지... 문서에서 앞부분에 나오는 것이 좋은 것이다.
  def locationscore(self, rows):
    locations = dict([(row[0], 1000000) for row in rows])    # 1000000는 최대 제한값 (각 단어들의 location 합)
    c(locations)
    for row in rows:
      loc = sum(row[1:])    # location1,location2,,, 단어 위치들을 모두 합한다.
      if loc < locations[row[0]]:
        locations[row[0]] = loc
    
    return self.normalizescores(locations, smallIsBetter=1)
  
  # 가중치 함수3(득점함수)
  # 단어 사이의 거리 알아보기(2개 이상의 복합 단어로 질의할 경우)
  def distancescore(self, rows):
    if len(rows[0]) <= 2:    # rows[0]의 내용은 (urlid, location1, location2,,)인데 길이가 2라면, 단어는 1개밖에 없다는 뜻 
      return dict([(row[0], 1.0) for row in rows])    # 모두 같은 점수로 통일

    mindistance = dict([(row[0], 1000000) for row in rows])

    for row in rows:
      dist = sum([abs(row[i] - row[i - 1]) for i in range(2, len(row))])    # 거리차를 계산
      if dist < mindistance[row[0]]: 
        mindistance[row[0]] = dist
    return self.normalizescores(mindistance, smallIsBetter=1)
  
  # 가중치 함수4(득점함수)
  # 06절 유입 링크 사용하기 에서 추가됨
  def inboundlinkscore(self, rows):
    uniqueurls = dict([(row[0], 1) for row in rows])
    inboundcount = dict([(urlid, self.con.execute('select count(*) from link where toid=%s' % urlid).fetchone()[0]) for urlid in uniqueurls])   
    return self.normalizescores(inboundcount)

  # 가중치 함수5(득점함수)
  def pagerankscore(self, rows):
    # 이전 sql에서는 self.cur.execute하고 나서... 따로 fetchone을 했는데,,, 아래 구문은 for 문 안에 있어서 한번에 할 수 밖에...
    pageranks = dict([(row[0], self.con.execute('select score from pagerank where urlid=%d' % row[0]).fetchone()[0]) for row in rows])
    maxrank = max(pageranks.values())
    if maxrank == 0:
      maxrank = 0.00001
    normalizedscores = dict([(u, float(l) / maxrank) for (u, l) in pageranks.items()])
    return normalizedscores
  
  # 가중치 함수6(득점함수)
  # 질의어가 a태그안의 텍스트인 경우
  def linktextscore(self, rows, wordids):
    linkscores = dict([(row[0], 0) for row in rows])
    for wordid in wordids:
      cur = self.con.execute('select link.fromid,link.toid from linkwords,link where wordid=%d and linkwords.linkid=link.rowid' % wordid)
      for (fromid, toid) in cur:
        if toid in linkscores:
          pr = self.con.execute('select score from pagerank where urlid=%d' % fromid).fetchone()[0]
          linkscores[toid] += pr
    maxscore = max(linkscores.values())
    if maxscore == 0:
      maxscore = 0.00001
    normalizedscores = dict([(u, float(l) / maxscore) for (u, l) in linkscores.items()])
    return normalizedscores
    
  # 가중치 함수6(득점함수)
  # 118p 클릭 학습 - 어떻게 사용하나???????????
  def nnscore(self, rows, wordids):
    from ch04_2 import searchnet
    mynet = searchnet('localhost_nn.db')
    mynet.maketables()
    
    urlids = [urlid for urlid in dict([(row[0], 1) for row in rows])]
    c(urlids)
    #학습 과정
    for r in range(10):
      mynet.trainquery(wordids, urlids, urlids[1])  # 임의 url (url을 클릭을 많이 하면, 순위를 뒤집을 수 있다.!!!
    
    nnres = mynet.getresult(wordids, urlids)
    c(nnres)
    scores = dict([(urlids[i], nnres[i]) for i in range(len(urlids))])
    return self.normalizescores(scores)
#########################################################################################################
    
# 96p *.db 파일로 검색하기
def practice5():
  practice4()
  c(searcher('localhost.db').getmatchrows('10 20'))    
  c(searcher('localhost.db').getmatchrows('출발'))    
  c(searcher('localhost.db').getmatchrows('출발 insert'))    
  c(searcher('localhost.db').getmatchrows('출발 insert title'))    
  # select w0.urlid,w0.location from wordlocation w0 where w0.wordid=6
  # select w0.urlid,w0.location,w1.location from wordlocation w0,wordlocation w1 where w0.wordid=6 and w0.urlid=w1.urlid and w1.wordid=2
  # select w0.urlid,w0.location,w1.location,w2.location from wordlocation w0,wordlocation w1,wordlocation w2 where w0.wordid=6 and w0.urlid=w1.urlid and w1.wordid=2 and w1.urlid=w2.urlid and w2.wordid=3
# practice5()

# 96p 05절 내용 기반 랭킹
def practice6():
  practice4()
  c(searcher('localhost.db').query('페이지 naver'))    # 2개 이상의 단어중 페이지에 없는 단어가 1개 있다면 무시된다..-_-;;
# practice6()

# 102p 06절 유입 링크 사용하기
# practice6()  #102p

# 105p 페이지랭크 만들기
def practice7():
  practice4()
  crawler('localhost.db').calculatepagerank()
# practice7()
# practice6()    # 106p

# 118p 클릭 학습 적용
practice6()














 

콘솔로그
239 >  create finished.
182 >  start crawling
C:\Python34\lib\site-packages\bs4\__init__.py:166: UserWarning: No parser was explicitly specified, so I'm using the best available HTML parser for this system ("html.parser"). This usually isn't a problem, but if you run this code on another system, or in a different virtual environment, it may use a different parser and behave differently.

To get rid of this warning, change this:

 BeautifulSoup([your markup])

to this:

 BeautifulSoup([your markup], "html.parser")

  markup_type=markup_type))
122 >  Indexing http://192.168.1.15:8080/start.html
122 >  Indexing http://192.168.1.15:8080/start/go20/20.html
122 >  Indexing http://192.168.1.15:8080/start/1.html
122 >  Indexing http://192.168.1.15:8080/start/2.html
122 >  Indexing http://192.168.1.15:8080/start/go10/10.html
122 >  Indexing http://192.168.1.15:8080/start/go20/22.html
122 >  Indexing http://192.168.1.15:8080/start/go20/21.html
157 >  this url 'http://192.168.1.15:8080/start/go10/10.html' is already indexed.
122 >  Indexing http://192.168.1.15:8080/start/go10/13.html
122 >  Indexing http://192.168.1.15:8080/start/go20/23.html
157 >  this url 'http://192.168.1.15:8080/start/go20/20.html' is already indexed.
122 >  Indexing http://192.168.1.15:8080/start/go10/11.html
122 >  Indexing http://192.168.1.15:8080/start/go10/12.html
359 >  select w0.urlid,w0.location,w1.location from wordlocation w0,wordlocation w1 where w0.wordid=11 and w0.urlid=w1.urlid and w1.wordid=22
463 >  {4: 1000000, 6: 1000000}
452 >  {4: 3, 6: 2}
282 >  [0.28413531533496345, 0.3141065454874244, 0.4577475993646154]
283 >  [0.13376582338538368, 0.35679063543142087, -0.11281807502885814]
284 >  [0.18592887432136948, 0.2778315828040204, 0.02544613051187923]
526 >  [4, 6]
532 >  [0.0010341455323867829, 0.8075322970407611]
426 >  {4: 4.006403121808109, 6: 6.991446997237285}
6.991447	http://192.168.1.15:8080/start/go10/11.html
4.006403	http://192.168.1.15:8080/start/go10/10.html
552 >  ([11, 22], [6, 4])

관련 ERD

 

 

 

 

 

#96p

검색어가 1개인 경우

select
  w0.urlid,
  w0.location
from
  wordlocation w0
where
  w0.wordid=6

 

검색어가 2개인 경우

select
  w0.urlid,
  w0.location,
  w1.location
from
  wordlocation w0,
  wordlocation w1
where
  w0.wordid=6
  and w0.urlid=w1.urlid
  and w1.wordid=2

 

검색어가 3개인 경우

select
  w0.urlid,
  w0.location,
  w1.location,
  w2.location
from
  wordlocation w0,
  wordlocation w1,
  wordlocation w2
where
  w0.wordid=6
  and w0.urlid=w1.urlid
  and w1.wordid=2
  and w1.urlid=w2.urlid
  and w2.wordid=3

 


-- *.db에 저장된 데이터를 좀더 자세히 볼 수 있는 쿼리

-- wordlocation 조회

select 

c.urlid

,u.url

,c.wordid

,w.word

,c.location

from wordlocation c

inner join urllist u

on c.urlid = u.rowid

inner join wordlist w

on c.wordid = w.rowid

;


-- link 조회

select

k.fromid

,u.url

,k.toid

,u2.url

from link k

inner join urllist u

on k.fromid = u.rowid

inner join urllist u2

on k.toid = u2.rowid

;


-- linkwords 조회

select

s.linkid

,k.fromid

,k.toid

,u.url as tourl

,s.wordid

,w.word

from linkwords s

inner join wordlist w

on s.wordid = w.rowid

inner join link k

on s.linkid = k.rowid

inner join urllist u

on k.toid = u.rowid

;


-- pagerank 조회

select

p.urlid

,u.url

,p.score

from pagerank p

inner join urllist u

on p.urlid = u.rowid

order by p.score desc