今年最初のコードは、前にJavaで書いたWikipediaのページ全文を格納したXMLをSAXでパースする処理を、Scalaで書き直した。
うちのマシンだとこの処理、75秒かかる。AthlonU X4 640(3Ghz)のマシン。SAXなんでメモリは対して使わないし、シングルコアしか使ってない。
こういう処理はJavaやScalaだと、いい加減に書いてもそこそこに速度が出るのでありがたい。
ちなみにこれでパースした結果をLuceneに全部放り込んだら(全部ストアもした)約21分かかった。
import org.xml.sax.InputSource
import org.xml.sax.helpers.DefaultHandler
import org.xml.sax.Attributes
import java.util.Date
import java.net.URLEncoder
import java.text.SimpleDateFormat
import javax.xml.parsers.SAXParser
import javax.xml.parsers.SAXParserFactory
/**
* Wikipediaのjawiki-latest-pages-articles.xmlを
* パースしてLuceneに登録する
* @author mwSoft
*/
class WikipediaArticleParser extends DefaultHandler {
val DATE_PARSE = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
val DATE_FORMAT = new SimpleDateFormat("yyyyMMddHHmmss")
val text = new StringBuffer()
var model: Model = null
var revision = false
var contributor = false
/** タグ開始 */
override def startElement(uri: String, localName: String, qName: String,
attributes: Attributes): Unit = {
if ("page" == qName) model = new Model
else if ("revision" == qName) revision = true
else if ("contributor" == qName) contributor = true
else if (!contributor && "comment" != qName)
text.setLength(0)
}
/** char追加 */
override def characters(ch: Array[Char], start: Int, length: Int): Unit = {
if (!contributor)
text.append(ch, start, length);
}
/** タグ終了 */
override def endElement(uri: String, localName: String, qName: String): Unit = {
val str = text.toString.trim
if ("text" == qName) model.text = str
else if ("title" == qName) setTitle(str)
else if ("timestamp" == qName) model.timestamp = DATE_PARSE.parse(str)
else if (!revision && "id" == qName)
model.id = str.toLong
else if (revision && !contributor && "id" == qName)
model.revisionId = str.toLong
else if ("revision" == qName) revision = false
else if ("contributor" == qName) contributor = false
else if ("page" == qName) {
//println(model)
//ここに登録とかなんかの処理を書く
}
}
/** Titleの設定 */
private def setTitle(title: String) {
model.title = text.toString
model.titleWord = extract
model.url = "http://ja.wikipedia.org/wiki/" + URLEncoder.encode(title, "utf-8")
// 邪魔者を排除してタイトルの単語自体っぽいところを抽出
def extract: String = {
val matcher = "(.*)_?\\(.*\\)".r.unapplySeq(title)
if (matcher != None && matcher.get.length > 0)
return matcher.get(0) + "\n"
return title
}
}
/** 登録するデータ構造 */
class Model {
var url: String = null
var source: String = "wikipedia"
var id: Long = -1
var title: String = null
var titleWord: String = null
var timestamp: Date = null
var revisionId: Long = -1
var text: String = null
override def toString = "url:" + url + "\n" + "source:" + source + "\n" +
"id:" + id + "\n" + "title:" + title + "\n" +
"titleWord:" + titleWord + "\n" + "timestamp:" + timestamp + "\n" +
"revisionId:" + revisionId + "\n"
}
}
/**
* Wikipediaの記事XMLを解析する
* @author mwSoft
*/
object WikipediaArticleParser {
def main(args: Array[String]) {
val start = System.currentTimeMillis
val filePath = "data/wikipedia/jawiki-latest-pages-articles.xml"
val is = new InputSource(filePath)
val saxf = SAXParserFactory.newInstance()
val saxParser = saxf.newSAXParser()
saxParser.parse(is, new WikipediaArticleParser)
println((System.currentTimeMillis - start) + "msec")
}
}