Fessでelasticsearchを利用する

elasticsearchはSolrのようなluceneベースの検索サーバですが、Solrよりもデータ解析系に向かっているものかと思います。
elasticsearchはいろいろな機能をプラグインとして提供していますが、Solrっぽい動きをしてくれるmocksolrpluginというのがあるので、それを使って、FessでSolrの代わりにelasticsearchを使ってみます。
まず、ここからelasticsearchをダウンロードします。
そして、それを展開します。

$ unzip elasticsearch-0.90.0.zip
$ cd elasticsearch-0.90.0/

次に、elasticsearch-mocksolrpluginをインストールします。
ですが、オリジナルのmocksolrpluginはelasticsearch 0.90.0で動かないので(そもそもあんまり動かない気が…)、修正したものをcodelibsから提供したのでそれを利用します。
オリジナルのmocksolrpluginが今後運用されるかどうかよくわからないので、フォークして独自路線を進むかどうかは今後考えるとして、とりあえずはそこにある最新のzipを利用してもらえればOKかと。
(ちなみに修正したソースコードはここのdevelopブランチにあります)

$ ./bin/plugin -install elasticsearch-mocksolrplugin -url http://maven.codelibs.org/org/codelibs/elasticsearch-mocksolrplugin/1.1.5-SNAPSHOT/elasticsearch-mocksolrplugin-1.1.5-20130507.051401-2.zip

上記でプラグインがインストールされます。
もし、プラグインのインストールに失敗したような場合は、一度、プラグインをアンインストールして再度インストールしてください。
プラグインのアンインストールは以下のコマンド。

$ ./bin/plugin -remove elasticsearch-mocksolrplugin

そして、elasticsearchを起動します。

$ ./bin/elasticsearch

次にelasticsearch上にインデックスを生成しておく。

$ curl -XPUT 'http://127.0.0.1:9200/solr/'

URL上のsolrの部分はインデックス名なので、別にsolrという名前でなくてもOKです。
次に事前にフィールドの型を登録しておきます。
elasticsearchは何もしないと自動で型判定をして、インデックスを生成するので、必要に応じて事前にマッピングという形で型登録をしておきます。
まぁ、elasticsearchはスキーマフリーという感じだけど、日付型とかあると事前に指定しておかないとうまくいかない場合もある気がするし、型とかが事前にわかっているなら、マッピングで指定しておいた方が良い気がします。
FessのSolrスキーマをベースに作ると以下の感じ。

$ curl -XPUT 'http://127.0.0.1:9200/solr/core1/_mapping' -d '
{
"core1" : {
"index_analyzer" : "standard",
"search_analyzer" : "standard",
"date_detection" : false,
"numeric_detection" : true,
"properties" : {
"id" : {"type" : "string", "store" : "yes", "index" : "not_analyzed"},
"parentId" : {"type" : "string", "store" : "yes", "index" : "not_analyzed"},
"segment" : {"type" : "string", "store" : "yes", "index" : "not_analyzed"},
"digest" : {"type" : "string", "store" : "yes"},
"boost" : {"type" : "float", "store" : "yes", "null_value" : 1.0},
"host" : {"type" : "string", "store" : "yes"},
"site" : {"type" : "string", "store" : "yes"},
"url" : {"type" : "string", "store" : "yes", "index" : "not_analyzed"},
"content" : {"type" : "string", "store" : "yes"},
"title" : {"type" : "string", "store" : "yes"},
"cache" : {"type" : "string", "store" : "yes", "index" : "not_analyzed"},
"tstamp" : {"type" : "solr_date", "store" : "yes"},
"anchor" : {"type" : "string", "store" : "yes", "index" : "not_analyzed"},
"contentLength" : {"type" : "long", "store" : "yes"},
"lastModified" : {"type" : "solr_date", "store" : "yes"},
"lang" : {"type" : "string", "store" : "yes"},
"mimetype" : {"type" : "string", "store" : "yes", "index" : "not_analyzed"},
"type" : {"type" : "string", "store" : "yes", "index" : "not_analyzed"},
"label" : {"type" : "string", "store" : "yes", "index" : "not_analyzed"},
"role" : {"type" : "string", "store" : "yes", "index" : "not_analyzed"}
}
}
}
'

次に、ここからFessをダウンロードして、インストールします。

$ cd ..
$ unzip fess-servver-8.0.0.zip
$ cd fess-server-8.0.0
$ chmod +x bin/*.sh

今回、Solrはいらないので削除しておきます。

$ rm -rf webapps/solr/

Fessの設定をSolrからelasticsearchに変更する。

$ vi webapps/fess/WEB-INF/classes/solrlib.dicon
...以下にSolrのパスを変更...
"http://127.0.0.1:9200/solr/core1/_solr"

そして、Fessを起動する。

$ ./bin/startup.sh

起動したら、管理者でログインします。
この辺は普通のFessと同様です。
http://127.0.0.1:8080/fess/admin/system/index にアクセスすると、solrServer1の状態がunknownと表示されるが気にしない。
現状、Function Queryがうまく処理できないので、http://127.0.0.1:8080/fess/admin/crawl/index で差分クロールのチェックを外して設定を保存する。
あとは、通常通りにクロール設定を作成してクロールを実行する。
クロールが完了したら、いつもどおりに http://127.0.0.1:8080/fess/ で検索してみてください。
検索結果に表示されればOKです。
今回、mappingでTokenizerとか設定していないので、必要に応じてその辺も設定すると良いかも。
オリジナルのものをいろいろと修正して、インデックスの登録と検索はできるようになったけど、Function Queryとか、まだ課題はある気がします。
一応、現状のものをオリジナルのところにpullリクエストはしてみたものの、特に反応はない感じです。
ということもあり、独自に作りなおしたほうが良いかな、とも思っています…。

Archivaのパスワードポリシー変更

Archivaを導入して3ヶ月くらい経つとパスワードの再設定を要求される。これはこれで良いことだとは思うのだけど、運用する手間が増えるのでちょっと微妙…。というわけで、設定の変え方だけど、ここに書いてある。~/.m2/secruity.propertiesファイルを作成して、

# Security Policies
security.policy.password.previous.count=6
security.policy.password.expiration.days=90
security.policy.password.expiration.enabled=true
security.policy.allowed.login.attempt=3
# Password Rules
security.policy.password.rule.alphanumeric.enabled=false
security.policy.password.rule.alphacount.enabled=true
security.policy.password.rule.alphacount.minimum=1
security.policy.password.rule.characterlength.enabled=true
security.policy.password.rule.characterlength.minimum=1
security.policy.password.rule.characterlength.maximum=8
security.policy.password.rule.musthave.enabled=true
security.policy.password.rule.numericalcount.enabled=true
security.policy.password.rule.numericalcount.minimum=1
security.policy.password.rule.reuse.enabled=true
security.policy.password.rule.nowhitespace.enabled=true

を適当に編集しておいておく。security.policy.password.expiration.daysとかを適当に変更すれば良いかと。conf/security.propertiesの方は何か動かなかったけど、詳しく調べていない。

SolrJ 4.2の変更点

Solr 4.2になって、SolrJのSolrQuery#addSortFieldがDeprecatedになった。つまり、

query.addSortField("hoge", ORDER.desc);

というのを

query.addSort("hoge", ORDER.desc);



query.addSort(new SortClause("hoge", ORDER.desc));

という感じに変更するみたい。この変更は順番の関係かしら…。

Solrの日付型

Fessではファイルの更新日時とかlongとしてもっていたのだけど、日付のファセットをやろうと思うとdate型にする必要があるようなので、型を変更することにした。そもそも、なんでlongにしていたかというと、いまいちSolrJ経由でdate型としての突っ込み方を調べていなかったからです…。(まぁ、簡単に言うと手抜きです…ごめんなさい) というわけで、今回、Solrでdate型を利用することにしたのだけど、Solrのschema.xml的には

<fieldType name="date" class="solr.TrieDateField" precisionStep="0" positionIncrementGap="0"/>
<fieldType name="tdate" class="solr.TrieDateField" precisionStep="6" positionIncrementGap="0"/>

というような型の定義があると思うけど、これを

<field name="tstamp" type="tdate" stored="true" indexed="true"/>

という感じで利用する。記述フォーマットについてはSolrのorg.apache.solr.schema.DateFieldのJavaDocとか見れば良いと思うけど、ISO 8601に従う感じで、XML Schema にある、より厳しくした感じの正規化した日付表現で以下のような感じ。

  • 1995-12-31T23:59:59Z
  • 1995-12-31T23:59:59.9Z
  • 1995-12-31T23:59:59.99Z
  • 1995-12-31T23:59:59.999Z

Javaのコードで上記の文字とDateへの変換はorg.apache.solr.common.util.DateUtilを使えば良さそう。パースの方はDateUtil.parseDate(String)で良いと思うけど、日付から文字列へはDateUtil.getThreadLocalDateFormat().format(date)という感じでやればよさそう。FessではFessFunctionsで実装して、JSP上からも${fe:〜}で利用している。

Archiva 1.4 M3のインストール

ArchivaはApacheから提供されているMavenなどのリポジトリ管理ツールである。Mavenなどをよく使うと成果物の置き場とかには悩むかと思うがそれを管理することができる。というわけで、説明はここにあるけど、1.4 M3を既存のTomcat 7などに入れる方法を書いておく。
まず、Archivaをここからダウンロードする。ダウンロードしたら

$ cd $TOMCAT_HOME
$ mkdir archiva
$ cp ~/Downloads/apache-archiva-js-1.4-M3.war archiva

という感じでディレクトリを作っておいておく。そんでさらに、derby-10.9.1.0.jar、activation-1.1.1.jar、mail-1.4.6-rc1.jarをMavenリポジトリなどから入手してlibに置く。

$ cp ~/Downloads/derby-10.9.1.0.jar ~/Downloads/activation-1.1.1.jar ~/Downloads/mail-1.4.6-rc1.jar lib

次にarchiva.xmlを生成する。

$ vi conf/Catalina/localhost/archiva.xml

内容は以下のような感じ。

<Context path="/archiva"
            docBase="${catalina.home}/archiva/apache-archiva-js-1.4-M3.war">
  <Resource name="jdbc/users" auth="Container" type="javax.sql.DataSource"
    username="sa" password="" driverClassName="org.apache.derby.jdbc.EmbeddedDriver"
    url="jdbc:derby:${catalina.home}/archiva/database/users;create=true" />
  <Resource name="jdbc/archiva" auth="Container" type="javax.sql.DataSource"
    username="sa" password="" driverClassName="org.apache.derby.jdbc.EmbeddedDriver"
    url="jdbc:derby:${catalina.home}/archiva/database/archiva;create=true" />
  <Resource name="mail/Session" auth="Container"
    type="javax.mail.Session" mail.smtp.host="localhost"/>
</Context>

そして、setenv.shに追記しておく。

$ vi bin/setenv.sh
export CATALINA_OPTS="$CATALINA_OPTS -Dappserver.home=$CATALINA_HOME -Dappserver.base=$CATALINA_HOME"

という感じであとはTomcatを起動すれば良い。