Blog からいい感じに名詞を抽出したい
オライリー先生の課題で Blog ごとの比較とクラスタリングをするという例題があって、例題が英語だったので、日本語で対応しようとがんばってた。
日本語というだけで一気に難易度が上がる。
英語圏は空白でパースするだけで済む筈ですが、日本語だと形態素解析を実行しなければならない所が大分骨ではあります。
とりあえず RSS 拾っていい感じに形態素解析することまで。
libraryDependencies ++= Seq( "net.white-azalea" %% "scala_curl" % "0.1", "rome" % "rome" % "1.0" )
を指定してほげっと
import java.io.StringReader import net.reduls.igo.Morpheme import scala.collection.JavaConversions._ object Utils { import net.azalea.curl._ implicit val config = HTTP.options import com.sun.syndication.io.SyndFeedInput import com.sun.syndication.feed.synd.SyndEntry case class Entry() case class Feed(title: String, url: String, uri: String, entries:String) object Feed { def apply(rss: String):Feed = { val input = new SyndFeedInput val feed = input.build(new StringReader(rss)) val allEntries = feed.getEntries.map(o => o.asInstanceOf[SyndEntry]).map(s => s.getDescription.getValue).toList.mkString new Feed(feed.getTitle(), feed.getLink(), feed.getUri(), allEntries) } } def getRss(url: String) = { val result = HTTP.get(url).bodyAsString("UTF-8") Feed(result) } def parse(message: String):List[Morpheme] = { import net.reduls.igo.Tagger val tagger = new Tagger("ipadic") tagger.parse(message).toList } } object Cluster extends App { val rsses = List( "http://white-azalea.hatenablog.jp/rss" ) def tagFilter(base: String) = { base.replaceAll("</?[a-zA-Z0-9]+>", "") .replaceAll("<[a-zA-Z0-9]+ [a-z]+=\".*?\">", "") } def contentFilter(tgt: Morpheme) = { tgt.feature.startsWith("名詞") && !tgt.surface.isEmpty && !tgt.surface.matches("^[!#$%&'()@0-9?_.,/:;{}<>=\\-\\[\\]\"+*¥[¥]。]+$") && !tgt.surface.matches("^[a-zA-Z]$") && !tgt.surface.matches("^[0-9]+$") } def count(values: collection.mutable.Map[String, Int], key: String) = { values.get(key).map(i => { values.put(key, (i + 1)) }).getOrElse( values.put(key, 1) ) values } val wordCounts = rsses.map(Utils.getRss).map(v => { val tokens = Utils.parse(tagFilter(v.entries)).filter(contentFilter).map(v => v.surface) val mutables = collection.mutable.Map.empty[String, Int] val result = tokens.foldLeft(mutables)((m, key) => count(m, key)) println(v.url) v.url -> result.toMap }) println(wordCounts) }
タグを除去するとか、意味の無い変数名(アルファベット1文字)とか、数字のみの文字列を除去。