カテゴリー: テクノロジー

Solrのフィールド名に日本語を使えるか

前回の記事に引き続き、今回はフィールド名に日本語を使えるかどうかを調査しました。

フィールド名の仕様については、Solrリファレンスガイドの”Field Type Definitions and Properties”に記載があります。

The name of the fieldType. This value gets used in field definitions, in the “type” attribute. It is strongly recommended that names consist of alphanumeric or underscore characters only and not start with a digit. This is not currently strictly enforced.

  • 英数字(先頭文字として数字は使えない)
  • アンダースコア

「今は厳密には強制していません」というのが微妙なところです。“Defining Fields”にもう少し詳しい説明がありました。

Field names should consist of alphanumeric or underscore characters only and not start with a digit. This is not currently strictly enforced, but other field names will not have first class support from all components and back compatibility is not guaranteed.

英数字とアンダースコア以外の文字も使えないことはないけど、全部のコンポーネントがサポートしているとは限らないよ、ということのようです。

フィールド名に日本語を使うとどういうことが起こるか試してみました。

まずtestという名のコレクションを作成します。

$ curl -s 'http://localhost:8983/solr/admin/collections?action=CREATE&name=test&numShards=1&replicationFactor=1'

「日付」というフィールドを追加します。

$ cat add_field_j.json 
{
  "add-field":{
     "name":"日付",
     "type":"pdate",
     "stored":true }
}
$ curl -s -X POST -H 'Content-type:application/json' -d @add_field_j.json http://localhost:8983/solr/test/schema

APIで「日付」フィールドが存在することを確認できます。

$ curl -s 'http://localhost:8983/solr/test/schema/fields/%E6%97%A5%E4%BB%98'
{
  "responseHeader":{
    "status":0,
    "QTime":0},
  "field":{
    "name":"日付",
    "type":"pdate",
    "stored":true}}

「日付」フィールドに値を持つデータを投入してみます。

$ cat j.json
{"日付":"2019-01-01"}
$ ./post -c test j.json

比較のため、”date”フィールドを追加してデータを投入します。

$ cat add_field_e.json
{
  "add-field":{
     "name":"date",
     "type":"pdate",
     "stored":true }
}
$ curl -s -X POST -H 'Content-type:application/json' -d @add_field_e.json http://localhost:8983/solr/test/schema
$ cat e.json
{"date":"1999-01-01"}
$ ./post -c test e.json

データがどう保持されているか比較します。

$ curl -s 'http://localhost:8983/solr/test/select?q=*%3A*&omitHeader=true'
{
  "response":{"numFound":2,"start":0,"docs":[
      {
        "id":"578b7513-831e-4ef3-bdb9-770268f27a7e",
        "__":["2019-01-01T00:00:00Z"],
        "_version_":1651454167605051392},
      {
        "date":"1999-01-01T00:00:00Z",
        "id":"892eb3b5-a648-45a5-80c1-5b975e8ebc47",
        "_version_":1651454169922404352}]
  }}

“date”の方は特に問題ありません。「日付」フィールドは無く”__”というフィールドに値が格納されています。値が配列になっていることから、「日付」フィールドの定義とは異なるフィールドとして扱われていることが分かります。何か別のダイナミックフィールドのルールにヒットしたようです。

当然検索もできません。

$ curl -s 'http://localhost:8983/solr/test/select?q=%E6%97%A5%E4%BB%98%3A%5B*%20TO%20*%5D&omitHeader=true'
{
  "response":{"numFound":0,"start":0,"docs":[]
  }}
$ curl -s 'http://localhost:8983/solr/test/select?q=date%3A%5B*%20TO%20*%5D&omitHeader=true'
{
  "response":{"numFound":1,"start":0,"docs":[
      {
        "date":"1999-01-01T00:00:00Z",
        "id":"892eb3b5-a648-45a5-80c1-5b975e8ebc47",
        "_version_":1651454169922404352}]
  }}

というわけで、割と基本的なところで躓いてしまいました。結論としては、フィールド名に日本語を使うのも実用としては無理ということになりそうです。


面倒な事をシステムでなんとかする

弊社では勤怠システムがWEBシステムになっているのですが、忘れることがあったのでえいやーでなんとかしてみました。

・WEB上に勤怠システムがある
・emailアドレスとパスワードでログインする必要がある
・システムではlaravelのtoken処理が使われているらしく、cookieとtokenも一致させなければいけない
・Macの起動と終了で勤務時間とみなす
・自分しか使わない前提でとりあえず動くもの

ひとまず出勤と退勤処理をするためのプログラムを作成
できあがったものが以下

#!/usr/bin/env bash

function usage {
  cat <<EOM
Usage: $(basename "$0") [OPTION]...
  -h Display help
  -e VALUE E-mail address
  -p VALUE Password
  -t VALUE Type(start, end)
EOM

  exit 2
}

API_HOST='kintai-system-no-host-dayo'
_EMAIL=''
_PASS=''
_TYPE='start'

while getopts ":e:p:t:h" optKey; do
  case "$optKey" in
    e)
      _EMAIL="${OPTARG}"
      ;;
    p)
      _PASS="${OPTARG}"
      ;;
    t)
      if [ "x${OPTARG}" = "xstart" ]; then
        _TYPE='start'
      elif [ "x${OPTARG}" = "xend" ]; then
        _TYPE='end'
      else
        echo "-t ${OPTARG}: unknown type."
        usage
      fi
      ;;
    '-h'|'--help'|* )
      usage
      ;;
  esac
done


if [ "x${_EMAIL}" = "x" ]; then
  read -p "E-mail address: " _EMAIL
fi

if [ "x${_PASS}" = "x" ]; then
  read -sp "Password: " _PASS
fi

# cookieの保存場所
tmpfile=$(mktemp)

# トークンの取得
_TOKEN=$(curl -s -c ${tmpfile} https://${API_HOST}/login | xmllint --html --xpath '//*form/input/@value' - | grep value= | sed 's/[^"]*"\([^"]*\)"[^"]*/\1/g')

# ログイン
curl -L -b ${tmpfile} -c ${tmpfile} -d "_token=${_TOKEN}&email=${_EMAIL}&password=${_PASS}" https://${API_HOST}/login

# 出勤もしくは退勤
curl -L -b ${tmpfile} -c ${tmpfile} -d "_token=${_TOKEN}" https://${API_HOST}/dashboard/${_TYPE}/

exit

適当なファイル名eiya-de-kintai.shとして保存し、実行権限をつけておきます。

$ chmod +x ~/eiya-de-kintai.sh



実行するには以下のようにします。
出勤

$ ~/eiya-de-kintai.sh -e email@example.splout.co.jp -p password-desu -t start


退勤

$ ~/eiya-de-kintai.sh -e email@example.splout.co.jp -p password-desu -t end

プログラムの内容は
・curlでログインページの取得を行い、一時ファイルにcookieを保存
 同時にレスポンスbodyからxpathでinput要素のvalueにあるtokenを取得
・取得したcookieとtokenとメールアドレス(-e)とパスワード(-p)をログインページへPOSTし、ログイン状態のcookieを保存
・出勤もしくは退勤(-tで指定)のエンドポイントへログイン状態のcookieを使いtokenをPOST

ログイン判定してないとかcookieが残骸として残る等かなり手を抜いているがひとまず気にしない。徐々に手を加えていく予定。

Macの起動と終了で処理を走らせるには、「Macの起動=アプリケーションの起動」、「終了=アプリケーションの終了」とみなすことにし、作成したシェルスクリプトを呼び出すApplescriptを作成しました。

Macに標準で入っているスクリプトエディタを起動

↑こんなアイコン

以下のコードを記述

on run
	do shell script "~/eiya-de-kintai.sh -e email@example.splout.co.jp -p password-desu -t start"
end run

on quit
	do shell script "~/eiya-de-kintai.sh -e email@example.splout.co.jp -p password-desu -t end"
	continue quit
end quit

これを
 ファイルフォーマット:アプリケーション
 オプション:ハンドラの実行後に終了しない。
で保存します。

出来上がったアプリケーションをMacのログイン時に実行されるようにします。
「システム環境設定」にある「ユーザとグループ」を開き
「ログイン項目」へ作成したアプリケーションの登録を行います。

以上でとりあえずのものが出来上がりました。

Macを起動し、ログインすると自動で出勤処理が行われます。
Macの終了時には自動で退勤処理が行われ、何も意識しなくても勤怠処理が行われるようになりました。


そう、エラーさえなければ・・・

アカウント情報を平文で書いているとかApplescript使うならシェルいらないのでは?とかエラー処理されていないとか、実用するにはまだまだまだまだ改善すべき箇所が多く残っていますが、ひとまず目標は達成しました。


SolrのReadOnlyモード

Solr 8.1から追加された機能にRead-Onlyモードがあります。SolrCloudでの運用時に利用できるモードです。リファレンスマニュアルの該当部分を翻訳してみました。

readOnly属性をtrueにセットするとコレクションはRead-Onlyモードに移行します。このモードではインデックスの更新リクエストは拒否されます。他のコレクションレベルのアクション(コレクションの追加/削除、レプリカの移動)はこのモードにおいても有効です。


(デフォルトの)read-writeモードからread-onlyモードへは以下の手順で移行されます。
・コレクション内のreadOnlyフラグが変更される
・すべての更新リクエストが403 FORBIDDENエラーで拒否される(継続中の長期実行リクエストは中止される)
・実行中の更新が強制的にコミットされる
(注意)大きなセグメントがバックグラウンドでマージされている最中であれば、この強制コミットは長時間に及ぶかもしれません。
・コレクションのRELOADアクションが実行される
readOnly属性が削除されるかfalseに設定されるかすると、更新リクエストが有効になりコレクションがリロードされます。

https://lucene.apache.org/solr/guide/8_2/collection-management.html#readonlymode

簡単な動作確認をしてみました。

$ curl 'http://localhost:8983/solr/admin/collections?action=CREATE&name=test_readonly&collection.configName=_default&numShards=1&wt=xml'

$ curl 'http://localhost:8983/solr/admin/collections?action=MODIFYCOLLECTION&collection=test_readonly&readOnly=true'
{
  "responseHeader":{
    "status":0,
    "QTime":476},
  "success":{
    "127.0.1.1:8983_solr":{
      "responseHeader":{
        "status":0,
        "QTime":350}}}}
$ bin/post -c test_readonly data.json 
SimplePostTool version 5.0.0
Posting files to [base] url http://localhost:8983/solr/test_readonly/update...
Entering auto mode. File endings considered are xml,json,jsonl,csv,pdf,doc,docx,ppt,pptx,xls,xlsx,odt,odp,ods,ott,otp,ots,rtf,htm,html,txt,log
POSTing file data.json (application/json) to [base]/json/docs
SimplePostTool: WARNING: Solr returned an error #403 (Forbidden) for url: http://localhost:8983/solr/test_readonly/update/json/docs
SimplePostTool: WARNING: Response: {
  "responseHeader":{
    "status":403,
    "QTime":207},
  "error":{
    "metadata":[
      "error-class","org.apache.solr.common.SolrException",
      "root-error-class","org.apache.solr.common.SolrException"],
    "msg":"Collection test_readonly is read-only.",
    "code":403}}
SimplePostTool: FATAL: Looks like Solr is secured and would not let us in. Try with another user in '-u' parameter

テスト用のコレクション(test_readonly)を作成し、MODIFYCOLLECTIONアクションでreadOnlyをtrueに設定してからドキュメントをポストするとリファレンスの説明通り403エラーになりました。

$ curl 'http://localhost:8983/solr/test_readonly/select?q=*%3A*&rows=1&start=0'
{
  "responseHeader":{
    "zkConnected":true,
    "status":0,
    "QTime":1,
    "params":{
      "q":"*:*",
      "start":"0",
      "rows":"1"}},
  "response":{"numFound":0,"start":0,"docs":[]
  }}

当然インデックスは空っぽのままです。

$ curl 'http://localhost:8983/solr/admin/collections?action=MODIFYCOLLECTION&collection=test_readonly&readOnly=false'
{
  "responseHeader":{
    "status":0,
    "QTime":466},
  "success":{
    "127.0.1.1:8983_solr":{
      "responseHeader":{
        "status":0,
        "QTime":344}}}}
	
$ bin/post -c test_readonly data.json 
SimplePostTool version 5.0.0
Posting files to [base] url http://localhost:8983/solr/test_readonly/update...
Entering auto mode. File endings considered are xml,json,jsonl,csv,pdf,doc,docx,ppt,pptx,xls,xlsx,odt,odp,ods,ott,otp,ots,rtf,htm,html,txt,log
POSTing file data.json (application/json) to [base]/json/docs
1 files indexed.
COMMITting Solr index changes to http://localhost:8983/solr/test_readonly/update...
Time spent: 0:00:01.420

次にMODIFYCOLLECTIONアクションでreadOnlyをfalseに戻してからドキュメントをポストしたところ、今度はエラー無しでアップデートできました。

$ curl 'http://localhost:8983/solr/test_readonly/select?q=*%3A*&rows=1&start=0'
{
  "responseHeader":{
    "zkConnected":true,
    "status":0,
    "QTime":0,
    "params":{
      "q":"*:*",
      "start":"0",
      "rows":"1"}},
  "response":{"numFound":9236,"start":0,"docs":[
      {
        "id":"158",
        "type":["官公庁"],
        "area":["住之江区"],
        "name":["軽自動車検査協会大阪主管事務所"],
        "address":["住之江区南港東3-4-62"],
        "_version_":1648645250184380416}]
  }}

クエリの結果からも、正しく更新できたことを確認できます。

ReadOnlyモードを使えば内容固定のインデックスを運用中に誤って更新してしまうことを防ぐことができて便利ですが、このモードはSolrCloudでのみ利用可能なので、その点は注意が必要です。


PHP LaravelとVue.jsでWebSocketしてみる

秋になると「紅葉見に行こうよ」と言いたくなるけど言う相手がいない。
マエダです。

気づいたら紅葉シーズン終わっていた。。

 

Laravelを触ってみてVue.jsってどんなもんだろうと調査してみる機会がありました。
他のメンバーがずっと以前の社内勉強会で発表してくれていた通りものすごく便利なことに気付かされました。。。
ただ長くjQueryに甘えていたのでこの場合はどうするの?がたくさん。

今回はWebSocketしてみました。

参考サイト

https://readouble.com/laravel/5.7/ja/broadcasting.html
https://qiita.com/zaburo/items/34289d4573f39113b25a

いきなり参考サイトですがこの手順通りに対応すれば動作確認できちゃいます。
ありがとうございました。

実行コマンド抜粋

npm install –save laravel-echo socket.io-client
composer require predis/predis
composer dump-autoload
npm install -g laravel-echo-server
laravel-echo-server init
laravel-echo-server start

URLをディレクトリ指定に

Nginx設定する。
sudo vi /etc/nginx/conf.d/app.conf

location /ws/{
    proxy_pass http://127.0.0.1:6001/;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header X-Forwarded-For $remote_addr;
}

jsのpathにディレクトリを指定する。
vi resources/js/bootstrap.js

import Echo from 'laravel-echo'
window.io = require('socket.io-client');
window.Echo = new Echo({
    broadcaster: 'socket.io',
    host: window.location.hostname,
    path: '/ws/socket.io',
});

window.Echo.channel('hoges')
    .listen('Hoge', (e) => {
        console.log(e);
    });

感想

ほんとに全然JavaScriptコードを書かずともLaravelでWebSocketを利用できることにシンプルに感動でした。
個人的にはメンバーに負けないようにVue.jsを理解を深めます!
「千里の道も一歩から」
https://jp.vuejs.org/


Microsoft Edge preview builds を触ってみる

Microsoft Edge(以下Edge)が Chromium を採用すると発表してから11ヵ月、もうすぐ1年になろうとしています。

そろそろベータ版も落ち着いたのではないかと思い、インストールから一通り触ってみた感想を書いてみます。

以下から Edge preview build のダウンロードができます。

Microsoft Edge Insider Channels
https://www.microsoftedgeinsider.com/ja-jp/download

お試しできるベータ版は3種類あり、今回は Dev ビルドをインストール。
この記事を書いている時点のバージョン情報は、「79.0.308.1 (公式ビルド) dev (64 ビット)」 となっています。

起動せよと呼ぶ声あり

起動時の画面がこちら。

Microsoft Edge preview build を開いた最初の画面

メニューはこんな感じです。

Microsoft Edge preview build のメニュー

現行版 Edge に比べてかなり Chrome に近い印象。

弊社サイトの Recruit ページを preview build と現行の Edge で表示させて並べてみました。

左が preview build, 右が現行版 Edge

CSS の解釈が違うのかベータ版だからなのか、ヘッダー(青い色の部分)の box-shadow が効いていません。

いくつかWebページを見て回りましたが、閲覧程度なら現行ブラウザとも遜色なく動作しているように見えます。
Edge Insider の「既知の問題」を見るとまだいくつかの問題は残っているようですが、随時修正されていくでしょう。

私は Chrome であり、Safari であり、Edge ではない

ユーザーエージェントは以下のようになっています。

Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3943.0 Safari/537.36 Edg/79.0.308.1

Mozilla、AppleWebKit、Chrome と並んでいますが、Edge ではなく Edg となっています。
preview build であるため Edge にはまだ至っていないということなのか、このまま本採用されるのか。
開発者視点だと気になる点ではあります。

見よ、Chrome アドオンは共にある

新しい特徴として、Chrome アドオンが利用できるようになるとのことなので試してみました。

試してみるアドオンは Picture-in-Picture Extension (by Google)
https://chrome.google.com/webstore/detail/picture-in-picture-extens/hkgfoiooedgoejojocmhlaklaeopbecg

Chrome ウェブストアを Edge で開くと画面上部にメッセージが。

「他のストアからの拡張機能を許可する」というボタンをクリックすると、拡張機能のページに「Chrome に追加」のボタンが現れます。
押してみると何事もなく拡張機能に追加されました。

実際に試してみると、

PIPを有効にしたときの表示

Edge の外に PIP の小さなプレイヤーが表示され動画が再生されています。
ただ、試した限りでは残念ながら一時停止ボタンが機能しませんでした。

やがて Chrome になる?

ここまでをまとめると「Chrome によく似た何か」であり、それ以外の感想は特に出てきませんでした。
あまりに Chrome 然とし過ぎていて、どちらを使っているのか分からなくなります。

まずは基本機能の安定動作。
そこからの独自機能の実装という方針なのだと思います。

今後、実装予定の新機能が色々発表されていますし、edge://flags/ を開くと WebVR や WebXR Device API 等、気になる名称の機能が試験段階として無効化されていることが分かります。

試験段階の機能 Collections

そして、試験段階にある Internet Explorer モードが IE ユーザーに受け入れられるのかどうか。

正直にいえば、新しい Edge に一番期待しているポイントです。

IE がなくても Edge で問題ないということになれば、多くのWeb開発者の救済への大きな一歩となるかもしれません。

しかし、Chrome に似た何かで終わる可能性もあり…。

Microsoft 様におかれましてはどうかうまくやってくださいと強く祈るばかりです。