mwSoft blog http://blog.mwsoft.jp/ ja http://blog.mwsoft.jp/article/178810685.html kuromoji-neologdを使った形態素解析 Lucene3系だった頃と書き方がちょっと変わってたのでメモしておく。とりあえず下記を参考にdependencyは記述されているものとする。https://github.com/codelibs/elasticsearch-analysis-kuromoji-neologd scala MW 2017-02-18T18:36:04+09:00 Lucene3系だった頃と書き方がちょっと変わってたのでメモしておく。

とりあえず下記を参考にdependencyは記述されているものとする。
https://github.com/codelibs/elasticsearch-analysis-kuromoji-neologd

JapaneseTokenizerを利用して形態素解析する。unicode normalize等はFilter等は使わずにベタ書きしている。

import java.io.StringReader
import java.text.Normalizer
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute
import org.codelibs.neologd.ipadic.lucene.analysis.ja.JapaneseTokenizer
import org.codelibs.neologd.ipadic.lucene.analysis.ja.tokenattributes.BaseFormAttribute
import org.codelibs.neologd.ipadic.lucene.analysis.ja.tokenattributes.InflectionAttribute
import org.codelibs.neologd.ipadic.lucene.analysis.ja.tokenattributes.PartOfSpeechAttribute
import org.codelibs.neologd.ipadic.lucene.analysis.ja.tokenattributes.ReadingAttribute
object HtmlParser extends App {
  val value = "今日は晴れておりますね"
  val normValue = Normalizer.normalize(value, Normalizer.Form.NFKC).toLowerCase
  val reader = new StringReader(normValue.toString())
  val stream = new JapaneseTokenizer(null, true, JapaneseTokenizer.Mode.NORMAL)
  stream.setReader(reader)
  stream.reset()
  while (stream.incrementToken()) {
    println(s"term=${stream.getAttribute(classOf[CharTermAttribute])}, " +
      s"baseForm=${stream.getAttribute(classOf[BaseFormAttribute]).getBaseForm}, " +
      s"partOfSpeach=${stream.getAttribute(classOf[PartOfSpeechAttribute]).getPartOfSpeech}, " +
      s"reading=${stream.getAttribute(classOf[ReadingAttribute]).getPronunciation}, " +
      s"inflectionForm=${stream.getAttribute(classOf[InflectionAttribute]).getInflectionForm}, " +
      s"inflectionType=${stream.getAttribute(classOf[InflectionAttribute]).getInflectionType}, ")
  }
  stream.close()
}

実行結果

term=今日, baseForm=null, partOfSpeach=名詞-副詞可能, reading=キョー, inflectionForm=null, inflectionType=null, 
term=は, baseForm=null, partOfSpeach=助詞-係助詞, reading=ワ, inflectionForm=null, inflectionType=null, 
term=晴れ, baseForm=晴れる, partOfSpeach=動詞-自立, reading=ハレ, inflectionForm=連用形, inflectionType=一段, 
term=て, baseForm=null, partOfSpeach=助詞-接続助詞, reading=テ, inflectionForm=null, inflectionType=null, 
term=おり, baseForm=おる, partOfSpeach=動詞-非自立, reading=オリ, inflectionForm=連用形, inflectionType=五段・ラ行, 
term=ます, baseForm=null, partOfSpeach=助動詞, reading=マス, inflectionForm=基本形, inflectionType=特殊・マス, 
term=ね, baseForm=null, partOfSpeach=助詞-終助詞, reading=ネ, inflectionForm=null, inflectionType=null, 
]]>
http://blog.mwsoft.jp/article/178119317.html Scala SparkでRowがMatchErrorを起こす こんな感じ。Exception in thread "main" scala.MatchError: [foo,28,995,0.0] (of class org.apache.spark.sql.catalyst.expressions.GenericRowWithSchema) scala MW 2016-12-21T23:00:00+09:00 こんな感じ。
Exception in thread "main" scala.MatchError: [foo,28,995,0.0] (of class org.apache.spark.sql.catalyst.expressions.GenericRowWithSchema)

String, Long, Long, Doubleをイメージしていたので、こんな感じでMatchさせようとしていた。

case Row(hostName: String, score1: Long, score2: Long, cost: Double) =>

中身を確認。

case x: GenericRowWithSchema => { println(x.getClass); println(x.schema) }
  #=> StructType(StructField(host_name,StringType,true), StructField(score1,LongType,true), StructField(score2,LongType,false), StructField(cost,DecimalType(1,1),false))

Doubleではなくjava.math.BigDecimalというだけだった。。。

case Row(hostName: String, score1: Long, score2: Long, cost: java.math.BigDecimal) =>
]]>
http://blog.mwsoft.jp/article/176816356.html JavaでAvroのGenericRecordの中身をループで見る やり方がわからなかったので調べた。getFieldsでSchema.Fieldの一覧を取ってそれをループさせれば良いようだ。Recordが入れ子になっている場合は型調べつつ再帰的にやれば子要素まで取れると思う(未確認)。Javaと言いつつコードはScala。まあ、同じようなものだし。 Java MW 2016-09-10T00:13:34+09:00 やり方がわからなかったので調べた。getFieldsでSchema.Fieldの一覧を取ってそれをループさせれば良いようだ。

Recordが入れ子になっている場合は型調べつつ再帰的にやれば子要素まで取れると思う(未確認)。

Javaと言いつつコードはScala。まあ、同じようなものだし。

import org.apache.avro.generic.GenericRecord
import scala.collection.JavaConversions._
def getGenericRecord(): GenericRecord = {
  // get generic record code
}
val record = getGenericRecord()
for (field <- record.getSchema.getFields) {
  // 方法1
  println(field.name, record.get(field.name))
  // 方法2
  println(field.name, record.get(field.pos))
}
GenericRecordのgetにはStringとInt双方の引数が取れるようになっていて、Fieldのnameを渡してもposを渡しても同じように取れる。 ]]>
http://blog.mwsoft.jp/article/176814592.html rails + postgresqlを動かしたメモ なんか久々にrails動かしたので手順をメモしておく。何年ぶりだろう。 Ruby MW 2016-09-09T20:28:51+09:00 なんか久々にrails動かしたので手順をメモしておく。何年ぶりだろう。

とりあえずrvmインストール。

$ gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
$ curl -sSL https://get.rvm.io | bash -s stable --ruby

ターミナルを立ち上げ直して.bashrcやら.bash_profileやらを読み込ませたあと、rubyを入れる。都合により.2.2.1を採用。

$ rvm list known
$ rvm install ruby-2.2.1
$ rvm use ruby-2.2.1

postgresqlを入れる。

$ sudo apt-get install postgresql-9.5 libpq-dev

bundleを入れる。

$ gem install bundler

JavascriptのRuntimeがないと後で言われるのでnodejs入れとく。

$ sudo apt-get install nodejs

postgresql上でユーザを作る。

$ sudo -u postgres psql
> create database foo_table
> CREATE USER bar_user with password 'buz_passwd';	
> GRANT ALL PRIVILEGES ON DATABASE foo_table to bar_user;

あとは立ち上げ。プロジェクトは既に出来合いのものがあるとする。

$ bin/bundle install
$ bin/rake db:migrate
$ bin/rails server

だいたいこんな感じで動いた。 ]]> http://blog.mwsoft.jp/article/176814376.html gnomeの端末でrvmでuseできなかった場合 ちょっとRubyを使う用事があったのでrvm入れてuseとか言ったら下記のエラーが出た。$ rvm use ruby-2.2.1RVM is not a function, selecting rubies with 'rvm use ...' will not work.You need to change your terminal emulator preferences to allow login shell.Sometimes it is required to .. Ruby MW 2016-09-09T19:57:58+09:00 ちょっとRubyを使う用事があったのでrvm入れてuseとか言ったら下記のエラーが出た。

$ rvm use ruby-2.2.1
RVM is not a function, selecting rubies with 'rvm use ...' will not work.
You need to change your terminal emulator preferences to allow login shell.
Sometimes it is required to use `/bin/bash --login` as the command.
Please visit https://rvm.io/integration/gnome-terminal/ for an example.

解決方法はStackOverflowに書いてあった。

http://stackoverflow.com/questions/9336596/rvm-installation-not-working-rvm-is-not-a-function

rvmは.bash_profileに設定書くけどGnome Shellとかだとデフォルトがインタラクティブシェルになってるから、ログインシェルにしないと読まないよね。とりあえず bash --login とか言っとけば動くよみたいな内容。

Gnomeのターミナルの設定に「ログインシェルを使う」みたいなのがあるので、そこをチェックすれば動くようになる。もしくは先に bash --login と言ってから打つか、source ~/.bash_profileするか、まあなんでもいいや。 ]]> http://blog.mwsoft.jp/article/176743263.html JavaでSlackにMessageを投稿する最小限のコード メッセージを飛ばすだけの用事で依存ライブラリを増やすのもなんだったので、最小限のメッセージを飛ばすだけのコードを書く。戻り値はレスポンスを文字列にしたもの。 Java MW 2016-09-04T16:40:04+09:00 メッセージを飛ばすだけの用事で依存ライブラリを増やすのもなんだったので、最小限のメッセージを飛ばすだけのコードを書く。戻り値はレスポンスを文字列にしたもの。

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
public class SimpleMessageSender {
	private static final String postUrl = "https://slack.com/api/chat.postMessage";
	public static String send(String token, String channel, String userName, String text)
			throws UnsupportedEncodingException, IOException {
		byte[] postData = String.format("token=%1s&channel=%2s&username=%3s&text=%4s", token,
				channel, userName, URLEncoder.encode(text, "utf-8")).getBytes();
		HttpURLConnection conn = (HttpURLConnection) new URL(postUrl).openConnection();
		conn.setDoOutput(true);
		conn.setRequestMethod("POST");
		conn.setRequestProperty("Content-Length", Integer.toString(postData.length));
		try (DataOutputStream wr = new DataOutputStream(conn.getOutputStream())) {
			wr.write(postData);
		}
		try (Scanner s = new Scanner(conn.getInputStream())) {
			return s.useDelimiter("\\A").hasNext() ? s.useDelimiter("\\A").next() : "";
		}
	}
}
]]>
http://blog.mwsoft.jp/article/176742443.html firefoxのデフォルトの文字サイズが小さく感じる時 新しくPCを買って触っていたところ、Firefoxで表示される文字サイズがどうも小さく感じることが多かった。デフォルトのズームサイズを変えてしまえばよかろうということで、変え方を探したところmozllaのフォーラムにやり方が書いてあった。about:config で layout.css.devPixelsPerPx の値を変えれば良いようだ。うちは1.25にしたらちょうど良いサイズになった。 Web MW 2016-09-04T14:50:26+09:00
デフォルトのズームサイズを変えてしまえばよかろうということで、変え方を探したところmozllaのフォーラムにやり方が書いてあった。

about:config で layout.css.devPixelsPerPx の値を変えれば良いようだ。うちは1.25にしたらちょうど良いサイズになった。 ]]>
http://blog.mwsoft.jp/article/176742353.html apt-getでopenjdkを入れる 普段はoracleのjdk installerを入れてるけど、openjdk入れたい時ってどうすればいいんだっけ。jreの場合はdefault-jreを入れるところだけど、jdkの場合はdefault-jdkで良いらしい。$ sudo apt-get install default-jdkこれで最新(この記事を書いている時点では1.8.0_91)が入った。defaultと書いておけば済むのは便利。前のバージョンを入れたい際は apt-get install openjdk-7.. Java MW 2016-09-04T14:38:50+09:00 普段はoracleのjdk installerを入れてるけど、openjdk入れたい時ってどうすればいいんだっけ。

jreの場合はdefault-jreを入れるところだけど、jdkの場合はdefault-jdkで良いらしい。

$ sudo apt-get install default-jdk

これで最新(この記事を書いている時点では1.8.0_91)が入った。defaultと書いておけば済むのは便利。

前のバージョンを入れたい際は apt-get install openjdk-7-jdk のようにバージョン付きのパッケージがあるっぽいけど未検証。 ]]> http://blog.mwsoft.jp/article/176706566.html JavaでHadoopのrmdirしたかった fs.rmdir(path) みたいなことができるかと思ったのだけど、API見てみるとおらぬ。 Java MW 2016-09-01T16:13:08+09:00 fs.rmdir(path) みたいなことができるかと思ったのだけど、API見てみるとおらぬ。

https://hadoop.apache.org/docs/r2.6.1/api/org/apache/hadoop/fs/FileSystem.html

じゃ、hadoop fs -rmdir path とやっているアレは何者かと見てみると、重要なところとしては下記のような記述になっていた。

if (item.fs.listStatus(item.path).length == 0) {
    if (!item.fs.delete(item.path, false)) {
        throw new PathIOException(item.toString());
    }
}
// https://github.com/gnudeep/hadoop-2.6/blob/master/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/Delete.java

listStatusして0だったら消しに行く感じらしい。まあ、これでいいか。 ]]> http://blog.mwsoft.jp/article/176605428.html linuxでフォルダ内のファイルを古いものからn件削除する n日経過したファイルとかじゃなく、古いものから順にn件消したい時ってどうするんだっけと思ったけど、ls -tで日付でソートした状態で出してからtailでn件を抽出してrmすれば良いか。$ ls -t | tail -100 | xargs rm linux MW 2016-08-25T03:33:59+09:00 n日経過したファイルとかじゃなく、古いものから順にn件消したい時ってどうするんだっけと思ったけど、ls -tで日付でソートした状態で出してからtailでn件を抽出してrmすれば良いか。

$ ls -t | tail -100 | xargs rm
]]>
http://blog.mwsoft.jp/article/176575948.html yumでg++を入れる yum g++ではないらしい。長らくUbuntu系しか使ってなかったので忘れてしまった。下記で入る。yum gcc-c++ linux MW 2016-08-22T16:32:22+09:00 yum g++ではないらしい。長らくUbuntu系しか使ってなかったので忘れてしまった。

下記で入る。

yum gcc-c++
]]>
http://blog.mwsoft.jp/article/176526474.html scala.util.Tryで複数の例外をcatchする方法がわからなかった Scalaのtry catchで複数の例外をまとめてcatchしたい場合は、こんな風に書ける。 scala MW 2016-08-18T23:00:00+09:00 Scalaのtry catchで複数の例外をまとめてcatchしたい場合は、こんな風に書ける。
  try {
    // do something
  } catch {
    case e @ (_: IOException | _: IllegalFormatException) => { e.printStackTrace() }
    case e => { throw e }
  }

scala.util.Tryで似たようなことをどうするか調べようとしたのだけど、いい方法が見つからずこんな書き方になった。

  scala.util.Try {
    // do something
  } match {
    case Success(v) => { /* success */ }
    case Failure(e) => {
      e match {
        case e @ (_: IOException | _: IllegalFormatException) => e.printStackTrace()
        case e => throw e
      }
    }
  }

まあ、いいか。 ]]> http://blog.mwsoft.jp/article/176463849.html pythonのjoblibでコア数以上の並列が可能か確認する sleepさせながら行う処理を100個ほど立ち上げたかったので、4コアのマシン上でちゃんとプロセスが100個並列で立ち上がってくれるか、それともどっかで頭打ちしてしまうのか確認する。 Python MW 2016-08-13T15:54:47+09:00 sleepさせながら行う処理を100個ほど立ち上げたかったので、4コアのマシン上でちゃんとプロセスが100個並列で立ち上がってくれるか、それともどっかで頭打ちしてしまうのか確認する。

下記はn_jobsを4に指定している。

import time
import joblib
def print_thread_number(thread_number):
    for i in range(3):
        print(thread_number, i)
        time.sleep(1)
joblib.Parallel(n_jobs=4)(joblib.delayed(print_thread_number)(i) for i in range(10))

結果

0 0
1 0
2 0
3 0
0 1
1 1
2 1
3 1
0 2
1 2
3 2
2 2
4 0
5 0
6 0
7 0
4 1
7 1
5 1
6 1
4 2
7 2
5 2
6 2
8 0
9 0
8 1
9 1
8 2
9 2

n_jobsで指定した4個ずつ、きちんと消化されている。

n_jobsを10にすると、10個まとめて実行される。コア数を多少超えても大丈夫なようだ。

0 0
1 0
2 0
3 0
4 0
5 0
6 0
7 0
8 0
9 0
0 1
4 1
1 1
3 1
2 1
5 1
6 1
7 1
9 1
8 1
0 2
4 2
1 2
3 2
2 2
5 2
6 2
7 2
9 2
8 2

100並列とかにしても問題なかった。

処理能力をしっかり食う処理を並列で実行させた場合はどうなるか。下記は重い処理を20並列でやらせた際のtop。

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+   COMMAND
 5862 user    20   0  185448  22452   4004 R  21.6  0.1   0:01.62 python
 5871 user    20   0  185448  22792   4320 R  21.6  0.1   0:01.60 python
 5866 user    20   0  185448  22780   4320 R  20.9  0.1   0:01.57 python
 5863 user    20   0  185448  22452   4004 R  19.6  0.1   0:01.57 python
 5865 user    20   0  185448  22776   4320 R  19.6  0.1   0:01.54 python
 5858 user    20   0  185448  22760   4320 R  19.3  0.1   0:01.50 python
 5870 user    20   0  185448  22788   4320 R  19.3  0.1   0:01.54 python
 5872 user    20   0  185448  22792   4320 R  19.3  0.1   0:01.50 python
 5859 user    20   0  185448  22700   4256 R  18.9  0.1   0:01.51 python
 5860 user    20   0  185448  22576   4128 R  18.9  0.1   0:01.53 python
 5864 user    20   0  185448  22452   4004 R  18.9  0.1   0:01.55 python
 5868 user    20   0  185448  22788   4320 R  18.9  0.1   0:01.51 python
 5869 user    20   0  185448  22788   4320 R  18.9  0.1   0:01.50 python
 5873 user    20   0  185448  22568   4096 R  18.9  0.1   0:01.49 python
 5874 user    20   0  185448  22568   4096 R  18.9  0.1   0:01.51 python
 5876 user    20   0  185448  22800   4320 R  18.9  0.1   0:01.48 python
 5857 user    20   0  185448  22760   4320 R  18.6  0.1   0:01.53 python
 5861 user    20   0  185448  22448   4004 R  18.6  0.1   0:01.50 python
 5867 user    20   0  185448  22788   4320 R  18.6  0.1   0:01.52 python
 5875 user    20   0  185448  22608   4128 R  18.6  0.1   0:01.48 python          

綺麗にCPUが取り合いになっている。とりあえず負荷が軽い行為であれば、並列数を上げることは問題なさそう。 ]]> http://blog.mwsoft.jp/article/176458287.html Python3でURLから{schema}://{domain}/を抜き出したい http://www.example.com/foo/bar/baz というURLがあった時に、http://www.example.com/ の部分だけ抜き出したかった。StackOverFlowにPython2での抜き出し方が書いてあった。Python3用だと下記のように書けるようだ。from urllib.parse import urlparseurl = 'http://www.example.com/foo/bar/baz''{uri.scheme}://{uri.. Python MW 2016-08-13T04:43:04+09:00 http://www.example.com/foo/bar/baz というURLがあった時に、http://www.example.com/ の部分だけ抜き出したかった。

StackOverFlowにPython2での抜き出し方が書いてあった。Python3用だと下記のように書けるようだ。

from urllib.parse import urlparse
url = 'http://www.example.com/foo/bar/baz'
'{uri.scheme}://{uri.netloc}/'.format(uri=urlparse(url))
  #=> http://www.example.com/
]]>
http://blog.mwsoft.jp/article/176188532.html numpyで数値が指定範囲にいない場合に、指定範囲のmin/maxに置き換えたい とある数値について、0.0〜1.0の間にいて欲しいのに-0.1とか1.1みたいな値が混ざっていた場合。 所感 MW 2016-07-23T02:40:29+09:00 とある数値について、0.0〜1.0の間にいて欲しいのに-0.1とか1.1みたいな値が混ざっていた場合。
# マイナスや1.0を超えた値が混ざる適当なDataFrameをでっち上げる
df = pd.DataFrame(1.3 * np.random.random([5, 2]) - 0.2, columns=['A', 'B'])
    #=>           A         B
    #=> 0  0.418959  0.127008
    #=> 1  0.766270  0.939455
    #=> 2  1.019421 -0.193150
    #=> 3  0.802732  0.909558
    #=> 4  0.197882 -0.067508

これを1.0以上だったら1.0に、0以下だったら0.0に変換したい。

これまで適当にこんな風に書いていた。

np.fmin(1.0, np.fmax(0.0, df))

どう考えても良い書き方とは思えないので調べたら、np.clipという関数が出てきた。引数に配列、min、maxの3つを指定することで範囲内に収められるらしい。

np.clip(df, 0.0, 1.0)
    #=>           A         B
    #=> 0  0.418959  0.127008
    #=> 1  0.766270  0.939455
    #=> 2  1.000000  0.000000
    #=> 3  0.802732  0.909558
    #=> 4  0.197882  0.000000
]]>