TECH PLAY

株式会社ラクス

株式会社ラクス の技術ブログ

935

はじめに こんにちは。新卒2年目のEngawaです。 今回はGASを用いてサーバーレスでLINEbotを作成しましたので紹介してきます。 はじめに GAS(Google Apps Script)とは bot作成 新規チャンネルの作成と設定 GAS作成 URLの発行 発行したURLの設定 実行 おわりに 参考 GAS( Google Apps Script)とは Google が提供しているプログラミング環境のことです。 スクリプト の言語は、 JavaScript をベースとしています。 GASについては以前このブログで分かりやすく書いている記事があるのでご覧ください。 tech-blog.rakus.co.jp bot 作成 新規チャンネルの作成と設定 はじめに LINE Developers を使用して新規チャンネルを作成していきます。 LINE Developersにアクセス後Lineのアカウントでログイン > 新規プロバイダーの作成 > 新規チャンネルの作成の流れで進めてください。 新規チャンネルの作成時、  LINEログイン 、 Messaging API 、 Clovaスキル のいずれかを選択する画面が表示されますが、 Messaging API を選択してください。あとは必須箇所を適当に埋めて同意すれば作成完了です。 作成完了後、作成したチャンネルを選択し、チャンネル基本設定の画面を下にスクロールすると アクセストークン の項目があるので 再発行 ボタンを押してアクセス トーク ンを発行しておいてください。GAS と紐づける際に必要になります。 さらに下にスクロールすると 自動応答メッセージ の項目があるので 設定はこちら のリンクをクリックして応答設定画面を開いてください。 詳細設定に 応答メッセージ と Webhook の項目があるので、 応答メッセージ:オフ Webhook:オン で設定してください。 設定変更後は画面を閉じて、作成したチャンネルのチャンネル基本設定の画面を更新してください。 GAS作成 以下を スクリプト エディタに記載します。 ACCESS _TOKEN部分には上記で発行したアクセス トーク ンを記入してください。 // アクセストークン var ACCESS_TOKEN = '' // メッセージが送付された際に、実行される関数 function doPost(e){ var replyToken = JSON.parse(e.postData.contents).events[0].replyToken; var userMessage = JSON.parse(e.postData.contents).events[0].message.text; var url = 'https://api.line.me/v2/bot/message/reply'; var headers = { 'Content-Type': 'application/json; charset=UTF-8' , 'Authorization': 'Bearer ' +ACCESS_TOKEN }; var payload = JSON.stringify({ //メッセージ送信内容 'replyToken': replyToken , 'messages': [{ 'type': 'text' , 'text': userMessage }] } ) var options = { 'headers' : headers , 'method' : 'post' , 'payload' : payload }; // メッセージを応答 UrlFetchApp.fetch(url ,options) } URLの発行 作成した スクリプト にアクセスできるように設定します。下記手順で実施してください。 ・ 公開 > ウェブアプリケーション として導入 ・ Execute the app as:me ・ Who has access to the app:Anyone,even anonymous(全員(匿名ユーザを含む)) ・Deplyボタンを押下するとURLが作成されます。 発行したURLの設定 作成したチャンネルを選択し、チャンネル基本設定の画面を下にスクロールすると Webhook送信 と Webhook URL ※SSLのみ対応 の項目があるので、 Webhook送信:利用する Webhook URL ※ SSL のみ対応:発行したURL をそれぞれ設定します。 これで作成と設定は完了です。 実行 bot 作成が完了したのであとは実行です。 チャンネル基本設定に LINEアプリへのQRコード があるので読み取って登録してください。 あとはLINE上で適当な文字を打ち込めば、打ち込んだメッセージを返してくれます。 今回は入力した文字列をそのまま返すようになっているのですが、特定の文字が打ち込まれた時に返すメッセージを指定するには スクリプト の一部を以下のように変更すれば可能です。 var reply = null; if(userMessage === 'おはよう'){ reply = 'ございます'; }else{ reply='さようなら'; } var payload = JSON.stringify({ //メッセージ送信内容 'replyToken': replyToken , 'messages': [{ 'type': 'text' , 'text': reply //ここを変えると送信するメッセージを変更できる }] } ) おわりに 今回はサーバーレスでLINEbotを作成しました。 API を用いて天気予報や電車遅延情報を取得し、返答メッセージとして設定しておくことで確認することもできます。 参考 tech-blog.rakus.co.jp エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 forms.gle イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! rakus.connpass.com
アバター
はじめに こんにちは。新卒2年目のtaku_76です。 前回記事 では、FirebaseのRealtime Databaseを利用してリアルタイムチャットを作成しましたが、 その他にも様々な機能があるということで今回はFirebase Authenticationを使ってログイン機能を実装してみましたので紹介します。 はじめに Firebase Authenticationとは 実装 Firebaseでプロジェクトの作成 ログイン方法の設定 ユーザーを新規登録する ログイン処理を行う おわりに 参考 Firebase Authenticationとは Firebase Authenticationはほとんどのアプリで必要となるユーザー認証を簡単に実装することができます。具体的にはパスワード認証や、 Google 、 Facebook 、 Twitter などのフェデレーションIDプロバイダを使用した認証を行うことができます。方法としては、 FirebaseUI を使用するか、Firebase Authentication SDK を使ってログイン方法を手動でアプリに統合することで、ユーザーをFirebaseアプリにログインさせることができます。今回はメールアドレスとパスワードを用いてユーザー認証機能を実装します。 実装 Firebaseでプロジェクトの作成 以下にアクセスしてプロジェクトを作成します。 https://firebase.google.com プロジェクトが作成できたらウェブアプリにFirebaseを追加します。 scriptタグが表示されるので、今回作成するファイルapplication.jsに貼り付けます。 ログイン方法の設定 ログイン方法はメール / パスワードを有効にしておきます。 index.htmlにdivタグを追加しておきます。 <div> メールアドレス<input id="mailAddress" type="mailAddress" required/> </div> <div> パスワード<input id="password" type="password" required/> </div> <button id="login">ログイン</button> <button id="register">新規登録</button> ユーザーを新規登録する createUserWithEmailAndPassword メソッドにmailAddressとpasswordを渡すことでユーザーの新規登録ができます。 //新規登録処理 register.addEventListener('click', function(e) { var mailAddress = document.getElementById('mailAddress').value; var password = document.getElementById('password').value; firebase.auth().createUserWithEmailAndPassword(mailAddress, password) .catch(function(error) { alert('登録できません(' + error.message + ')'); }); }); メールアドレスとパスワードを入力して新規登録ボタンを押します。 すると以下のようにfirebaseの画面ではユーザーが登録されていることがわかります。 ログイン処理を行う signInWithEmailAndPasswordメソッドにmailAddressとpasswordを渡すことでログイン処理ができます。 //ログイン処理 login.addEventListener('click', function(e) { var mailAddress = document.getElementById('mailAddress').value; var password = document.getElementById('password').value; firebase.auth().signInWithEmailAndPassword(mailAddress, password) .catch(function(error) { alert('ログインできません(' + error.message + ')'); }); }); そしてonAuthStateChanged メソッドを使用して正常にログインができているか判定します。正常にログインできていれば、ユーザーに関する情報を取得できます。今回はログインできたことだけを確認するためにalertでメッセージを出す以外の処理は行なっていません。 //認証状態の確認 firebase.auth().onAuthStateChanged(function(user) { if(user) { //ログイン状態 alert("ログインに成功しました"); }else{ //ログアウト状態 } }); これで先ほど追加したユーザー情報を入力してログインを行うと以下のようになります。 ちなみに存在しないユーザーでログインすると以下のようなエラーが出ます。 これでユーザーを新規登録してログインするまでの処理は完了しました。 今回は実装を行なっていませんが、ログアウトについてはsignOutメソッドを使用することによって実装できます。 おわりに Firebase Authenticationを使ってユーザー認証を実装しましたがかなり手軽に実装できました。 今回はメールアドレスとパスワードを使用した認証でしたが、その他の認証も簡単に実装できるとのことなので試していきたいと思います。 参考 www.topgate.co.jp firebase.google.com エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
はじめに こんにちは、新卒2年目のyk_itgです。 業務の中で内容が同じ大量のテストデータが必要なテストがあったのですが、手作業で作成するとたくさんの手順を踏まなくてはならなかったり、入力を間違えたりして大変なので、なんとか SQL でできないか考えてみました。 はじめに 例えばこんなデータ 複製する 1. コピーしたいデータをtmpテーブルにコピーする 2. 変更したい部分のみを書き換える 3. 編集したデータを元のテーブルに挿入する 実行結果 関数にしてみる 実行結果 終わりに 例えばこんなデータ 例えばこのような感じのデータがあったとします。 CREATE TABLE chohyo ( chohyo_id INTEGER PRIMARY KEY, status INTEGER , user_name TEXT, title TEXT, hoge_flag INTEGER , total_price INTEGER ); CREATE SEQUENCE chohyo_sequence; CREATE TABLE chohyo_meisai ( chohyo_id INTEGER , meisai_number INTEGER , hoge_name TEXT, price INTEGER , PRIMARY KEY(chohyo_id, meisai_number), FOREIGN KEY(chohyo_id) references chohyo (chohyo_id) on delete cascade ); chohyo と chohyo_meisai は1:多の関係で、chohyoを作成する毎にシーケンスによってidに値が割り振られていくイメージです。 postgres=# SELECT * FROM chohyo WHERE chohyo_id = 1 ; -[ RECORD 1 ] ------------ chohyo_id | 1 status | 0 user_name | taro title | テスト帳票 1 hoge_flag | 0 total_price | 1000 postgres=# SELECT * FROM chohyo_meisai WHERE chohyo_id = 1 ; -[ RECORD 1 ]-+ --------- chohyo_id | 1 meisai_number | 0 hoge_name | コーヒー price | 500 -[ RECORD 2 ]-+ --------- chohyo_id | 1 meisai_number | 1 hoge_name | パン price | 500 今回はこのデータを複製する方法を考えていきます。 複製する SQL でテスト用のダミーデータを作成する方法としては作成したいデータの値を入れたINSERT文を作る、COPYを使う方法等ありますが、それぞれカラムを追加したときに対応する必要があったり、ファイルを操作する必要があったりで面倒です。 なるべくデータベース内で完結してほしいので、以下の手順で複製していきます。 コピーしたいデータをtmpテーブルにコピーする 変更したい部分のみを書き換える 編集したデータを元のテーブルに挿入する 1. コピーしたいデータをtmpテーブルにコピーする CREATE TABLE AS 文 *1 を使って、コピーするデータをtmpテーブルにコピーします。 TEMPORARY を指定するとセッションが切れたときにtmpテーブルは削除されるので、不要なデータが残る心配が無くなります。 下の SQL を実行する前に \set id 1 や psql -v id=1 などでコピーしたいデータを指定しておいてください。 CREATE TEMPORARY TABLE tmp_chohyo AS SELECT * FROM chohyo WHERE chohyo_id = :id; CREATE TEMPORARY TABLE tmp_chohyo_meisai AS SELECT * FROM chohyo_meisai WHERE chohyo_id = :id; 2. 変更したい部分のみを書き換える tmpテーブルにデータをコピーできたので、次は加工します。 下の SQL では chohyo の status 以外はそのままにして、 chohyo_id をシーケンスによって採番しています。 UPDATE tmp_chohyo SET chohyo_id = nextval( ' chohyo_sequence ' ), status = 1 ; UPDATE tmp_chohyo_meisai SET chohyo_id = ( SELECT chohyo_id FROM tmp_chohyo); 3. 編集したデータを元のテーブルに挿入する あとは加工したデータを元のテーブルに挿入するだけです。 INSERT INTO chohyo SELECT * FROM tmp_chohyo; INSERT INTO chohyo_meisai SELECT * FROM tmp_chohyo_meisai; 実行結果 postgres=# SELECT COUNT (*) FROM chohyo WHERE user_name = ' taro ' ; -[ RECORD 1 ] count | 2 関数にしてみる 上の SQL ではデータごとに1回実行しなくてはならず面倒なので、 PL/pgSQL *2 の関数にしてみます。 長くなりそうなので説明は省きますが、このような感じになります。 CREATE OR REPLACE FUNCTION copy_chohyo(chohyoId integer , count integer ) RETURNS VOID AS $$ DECLARE recordCount integer ; nextId integer ; resultChohyoCount integer ; resultMeisaiCount integer ; BEGIN SELECT COUNT (*) FROM chohyo WHERE chohyo_id = chohyoId INTO recordCount; RAISE NOTICE ' 件数 = % ' , recordCount; IF recordCount <> 1 THEN RETURN ; END IF ; -- テーブル構造をコピー CREATE TEMPORARY TABLE tmp_chohyo AS SELECT * FROM chohyo WHERE false ; CREATE TEMPORARY TABLE tmp_chohyo_meisai AS SELECT * FROM chohyo_meisai WHERE false ; -- コピーする数だけtmpにコピー&加工 FOR i IN 1 .. count LOOP INSERT INTO tmp_chohyo SELECT * FROM chohyo WHERE chohyo_id = chohyoId; INSERT INTO tmp_chohyo_meisai SELECT * FROM chohyo_meisai WHERE chohyo_id = chohyoId; -- あらかじめ次の値を保存 SELECT nextval( ' chohyo_sequence ' ) AS next_id INTO nextId; UPDATE tmp_chohyo SET chohyo_id = nextId WHERE chohyo_id = chohyoId; UPDATE tmp_chohyo_meisai SET chohyo_id = nextId WHERE chohyo_id = chohyoId; END LOOP ; -- コピーデータを挿入 INSERT INTO chohyo SELECT * FROM tmp_chohyo; GET DIAGNOSTICS resultChohyoCount = ROW_COUNT; RAISE NOTICE ' chohyo の挿入件数 = % ' , resultChohyoCount; INSERT INTO chohyo_meisai SELECT * FROM tmp_chohyo_meisai; GET DIAGNOSTICS resultMeisaiCount = ROW_COUNT; RAISE NOTICE ' chohyo_meisai の挿入件数 = % ' , resultMeisaiCount; -- 完了後処理 DROP TABLE tmp_chohyo; DROP TABLE tmp_chohyo_meisai; RETURN ; END ; $$ LANGUAGE plpgsql; 実行結果 postgres=# SELECT copy_chohyo( 1 , 5 ); NOTICE: 件数 = 1 NOTICE: chohyo の挿入件数 = 5 NOTICE: chohyo_meisai の挿入件数 = 10 -[ RECORD 1 ]- copy_chohyo | postgres=# SELECT COUNT (*) FROM chohyo WHERE user_name = ' taro ' ; -[ RECORD 1 ] count | 6 終わりに 今回は SQL のみでシーケンス採番付きのテストデータを複製する方法を考えてみましたが、いかがでしたでしょうか。 テストでデータを複製する際の参考になれば幸いです。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 forms.gle イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! rakus.connpass.com *1 : https://www.postgresql.jp/document/10/html/sql-createtableas.html *2 : https://www.postgresql.jp/document/9.4/html/plpgsql.html
アバター
はじめに こんにちは、aa_cryingです。 早いもので入社から1年半が経ちました。 はじめに kindle unlimitedとは 脱初心者のJavaScript力を底上げするための本 「巻き上げ」とは おわりに kindle unlimitedとは kindle unlimitedとは、 Amazon が展開する、月額制の 電子書籍 読み放題サービスです。 なんと今なら 30日間無料 で様々な書籍・漫画が読めるので、 JavaScript の技術書籍を探してみました。 脱初心者の JavaScript 力を底上げするための本 Amazon で「 JavaScript 脱初心者」と検索すると検索結果の一番上に出てくる書籍です。 脱初心者のJavaScript力を底上げするための本/天田士郎 こちらの書籍では、1章は基本的なコーディングテクニック等が記載されていますが、 2章以降では無名関数・即時関数の使い方や、巻き上げ等 脱初心者 に必要な知識が説明されています。 コードとともに説明されているため、実際に動きを確かめながら進めることが出来ます。 私は JavaScript 特有の「巻き上げ」という概念を知らず、この書籍を読んで初めて知りましたので、抜粋して紹介させていただきます。 「巻き上げ」とは 以下は「巻き上げ」が起こるコードの例になります。 var a = 'hoge' ; var f = function () { console.log(a); var a = 'fuga' ; console.log(a); } f(); この例では、一見すると1回目のconsole.log(a)では 「 hoge 」 が出力されそうですが、 「undefined」 になります。 JavaScript では、関数内のどの位置でもvar文を利用して変数の宣言ができます。 しかし、これらの変数は関数内のいかなる場所で宣言されたとしても「この関数の先頭で宣言された」とみなされます。 このため、以下の例と同じになります。 var a = 'hoge' ; var f = function () { var a; console.log(a); a = 'fuga' ; console.log(a); } f(); aは1回目のconsole.log(a)の時点では新たに宣言だけされており、代入までは行われません。 (巻き上げられるのは宣言部分のみ) ですので、1回目のconsole.log(a)の時点では 「undefined」 となるのです。 このように、他の JavaScript 特有の規則等についても例を交えてわかりやすく説明されており、 脱初心者 には非常に為になる書籍でした。 おわりに 今回は kindle unlimitedで無料で読める JavaScript の脱初心者本について紹介させていただきました。 技術書籍を読みたいけれど何から読んだらよいかわからない 本屋で探すのが面倒 という方は、 kindle unlimitedで探してみるのもアリかもしれません。 他にも読んでみた書籍がありますので、そちらは次の機会に紹介させていただければと思います。
アバター
はじめに こんにちは、新卒のcrowd_kです。 今年の4月に入社をし、社会人になって約半年が経ちました。 入社するまでプログラミング未経験者だったので、日々の業務で新しい知識や様々な発見の連続に翻弄されながら、でもどこかで楽しみつつ学習をする毎日を過ごしています。 その中で1つ気になったことがありました。 それは、プログラム内のインデントを、タブ文字(\t)ではなくスペースで作成する方針になっていたことです。 プログラミング歴の浅い私は全く意識せず、使用している Eclipse の初期設定であるタブを用いていました。なので改行等をすると、作成されるインデントはタブで構成されていることになります。 しかし、コードのレビューを依頼した際に上記の方針(インデントはスペースで作成する)に引っ掛かり、コード内のタブをすべてスペースに置き換えるという作業を行いました。 最初はなにも疑わずに修正していましたが、後々考えてみるとなぜなんだろうと疑問を持ちました。 「タブを用いることで生じるバグなどがあったりするのか?」 考えてみても答えは出ないので、調べてみることにしました。 インデント そもそもプログラミングにおけるインデントとは、一般的に 「 プログラムのネスト構造を読み手にわかりやすく表現するために行頭の位置を変化させること 」 だと思います。 if (a == b){ if (b == c){ System.out.println( "aとbとcは全て同じ" ); } System.out.println( "aとbは同じ" ); } else { if (b != c){ System.out.println( "bとcは同じ" ); } System.out.println( "aとbは同じではない" ); } 上のコードのように行頭をそろえたほうが見やすくなります。プログラミング経験者なら誰でも行ったことがあるかと思います。 このインデントを作るための空欄を表現するためにタブを使っていたところ、「スペースに直せ」とはじかれたわけです。 調べてみると、「インデントをタブで行う人派」(以後タブ派)と「インデントをスペースで行う人派」(以後スペース派)で分かれよく論争が起きる、答えのない有名な議題の1つだということがわかりました。 以下に調べた結果をまとめていこうと思います。 タブ・スペース、それぞれの違い 結論から言うと タブを使用した結果、何かの不具合やバグが発生するなどといったデメリットは、ほぼ発生しないようです。 しかし、環境によってタブが半角スペース×4、または×2になってしまったり、単なる半角スペースに置換されてしまったりなどインデントの幅が変化し、見た目が変わってしまう事があるらしく、「ほぼ発生しない」という表現にしました。(逆に見た目を変化せることができるということです) この、環境によって見た目が変わってしまう、または変えることができる特徴こそが、この論争の重要なポイントのようです。 流行りの歴史 まず最初に流行ったのは「タブ」だったそうです。 理由は単純でスペースでインデントを作るには、そのキーを何回も押すのが面倒な点と、文字数を減らすことができるのでファイルサイズも抑えることができる点、この2点が挙げられます。 しかし、先に述べたデメリットが発覚したことで、回避するためにスペース×4でインデントを作るのが主流になりました。 また、そこから派生してスペース×2をインデントとする人たちも現れたようです。これは、インデントの幅が大きくなった時、スペースの個数を間違えることが多く、その問題を改善するためにインデントに使うスペース数を減らした結果だそうです。 それぞれの長所短所を簡単にまとめると以下のようになります。   タブ スペース メリット  入力回数が少ない ファイルサイズを抑えることができる エディターによって自由にインデントの幅を設定することができる どの環境でも同じ見た目にすることができる (環境に依存しない) デメリット 環境によって見た目が変化する 打ち込む回数が多く手間になる 打ち込む回数にミスが生じた場合、見た目が悪くなる 上に記した歴史は、あくまで流行りでありどの時代でもタブ派とスペース派は混在し、どちらを使うのが良いかという論争を繰り広げてきました。 両者にはそれぞれ長所と短所があるため、いつになってもこの論争は終わらないのです。 それぞれの派閥のエンジニアの意見を見ると以下のような意見がみられました。 タブ派 ・ エディタ等の設定を変更すれば好きなように幅を変化っさせることができるので、相手にとって一番見やすい形に都度変更してもらうことができる ・ タブのほうが操作が簡単であり、事実上タブによるデメリットはないので効率を考えるとタブを使うべき ・スペースの数をそろえるのが面倒 ・ インデントの幅が正しいのかを簡単に見分けることができる                                 ...etc スペース派 ・ コードを綺麗に見せるには自分が意図した通りに表示させる必要がある ・ 環境によって表示が変わってしまうのでは、相手に自分の伝えたいことが伝わらないかもしれない ・ エンジニアならファイルサイズが小さくなるメリットより見やすさを重視すべき ・ 全角スペースを探すために非表示文字を表示させる際に、スペース・タブが混在していると探すのが大変                                 ...etc コーディングのセンス次第 私は、両者の様々な意見をみて書き手の性質によるのではないかなと感じました。 コードを何かの芸術作品に例えて考えると、 自分が作り上げた作品を自分が一番綺麗だと思う見せ方で見せたいから、作品の置き方、見る角度、照明等をすべて指定するのがスペース派 作品を見せる際の照明等のこだわりはなく、見る人が一番だと思う方法で見てもらえるのが一番だと考えるのがタブ派 のどちらが良いかという話になるんじゃないかなと思います。 どちらも読み手にいかにプログラムコードを綺麗に見せるかに重点が置いてあり、それぞれがいいと思うものを使うのが一番かなと思いました。 しかし、1点だけ注意しなければならないことが。 複数人で開発を行う場合、それぞれが好みのインデントのルールで開発を行うと見た目がぐちゃぐちゃになり、非常に見づらいコードになってしまいます。 なので、その際はプロジェクトのルールに従う必要があります。(言うまでもないかもしれませんが...) これを考えると、現在はスペース派が多数派になっているので、こだわりがないのならスペースに慣れたほうがいいかもしれません。 終わりに 調べた結果、タブを使用してもバグ等の原因になりえないことがわかりましたが、コーディングに関して深い理由があるんだなということに気づけました。 また、気になったことを記事にしていこうかなと思います。
アバター
こんにちは。west-c です。 書籍「エンジニアの知的生産術 ──効率的に学び、整理し、アウトプットする」を読み、個人的に刺さる内容でしたので、今回はこちらの本を紹介します。 エンジニアの知的生産術 ──効率的に学び、整理し、アウトプットする (WEB+DB PRESS plusシリーズ) 作者: 西尾 泰和 発売日: 2018/08/10 メディア: 単行本(ソフトカバー) なお、先日社内で開催されたビアバッシュでもこの書籍の紹介を行いました。 tech-blog.rakus.co.jp 以下のような方におすすめの書籍です 勉強しなくては思うが勉強の仕方が分からない やる気が起きない・維持できない そもそも何から勉強すれば良いのか分からない 私はまさに上記のような悩みを持っていました。 若手の方を中心に、自己研鑽のための学習方法に悩んでいる方におすすめします。 「知的生産」とは 知的生産とは『 知識を用いて価値を生み出すこと 』と書籍内では定義されています。 例えばプログラムを作成したり執筆を行い書籍を出版したりする等、インプットした知識をもとに新たな価値を生み出すことが知的生産にあたります。 その中でも、どのように学習するか、言い換えるとどのように知識をインプットし自身の中に定着させるかについての記述が特にためになる書籍でした。 学びのサイクル 学習は「情報収集」「モデル化」「検証」の3要素を繰り返すことで成り立っていると書かれています。 情報収集:知識をインプットするフェーズ モデル化:情報収集した知識を整理するフェーズ 検証:アウトプットを通じてモデル化した知識が正しく理解できているか確認するフェーズ 自身の今までの学習方法を振り返ると、情報収集は行うものの知識を腹落ちさせるためのモデル化および検証のフェーズが足りていませんでした。 書籍などを読んでも自分の知識として定着していない感覚があったのも、この学習のサイクルを回すことができていなかったためだと感じました。 また、「情報収集は自分の知りたいと思うところからつまみ食いするような学習方法でも良い」との記述が書籍内でありました。 私の場合、書籍を読む際には最初から最後のページまで読まなければならないという先入観があり、結果として最後までやる気を維持できず投げ出してしまうことも多々あったため新たな発見でした。 学びのサイクルを実践してみる 早速実践しなくては読んだ意味が無いということで、『「エンジニアの知的生産術」を読み学びのエッセンスを習得する』という学習を、学びのサイクルに当てはめて実践してみました。 1. 情報収集 今回は書籍を読むことがこのフェーズにあたります。 私は Kindle 版で読んでいたため、印象的な文章は適宜ハイライトを付けながら読み進めました。 2. モデル化 書籍から学んだ内容を整理するフェーズです。ここでは、考えをまとめる方法として書籍内で紹介されていた「書き出し法」「 KJ法 」を利用して整理を行いました。 ①得た情報を書き出す ハイライトを付けた内容を中心に、書籍から得た情報を付箋に書き出しました。 書籍内だけに限らず、別の書籍の関連する部分 *1 や自身が感じたことについても同様に書き出しています。 ②分類する 書き出した付箋を、関連するもの同士グループ化し、そのグループを表す表札を付けます。 ここでは、「この記述はどの章にあった」ということを忘れて、付箋同士を眺めて新たな関連を見つけることを意識しました。 ③図解化する 分類した単位で付箋を展開し、各付箋の繋がりを図示していきます。 この図示した内容をもとに、社内のビアバッシュで紹介を行うためのスライドを作成しました。 3. 検証 社内のビアバッシュにて紹介を行い、伝えたいことが伝わっているかの検証を行いました。 若手メンバーを中心にためになったという感想をいただいたので、自身が書籍を読んだときに感じた気持ちが多少なりとも伝わったのではないかと思います。 また、本記事による文章化は二度目の検証という意味合いもあります。 実践してみて スライドの作成中、理解が曖昧な箇所に気付き再度本を読み返すことがありました。 モデル化・検証により分かったつもりで実は理解できていなかった点に気付くことができたことから、復習として有効であり、また得た知識も自身の中に定着しているように感じました。 加えて、モデル化の過程でフラットな階層で得た情報を一覧化したことで、別の章に記載されている事同士の関連に気付き新たな発見があった点も収穫でした。 一方で以下のような壁にもぶつかり、書き出し法・ KJ法 の難しさを痛感しました。 KJ法 は付箋100枚程度からが有効、との記述が書籍内であったが100枚書き出すのはなかなか難しい *2 付箋の分類は意識しても章単位にまとまってしまいがち スライド作成の段階で話の進め方に悩み、付箋の繋がりをきちんと図解化できていないことが露呈する 上記のような難しさは感じましたが、考えを整理する方法として手応えは感じましたので今後も実践して感覚を掴めればと思います。 感想 タイトルに「エンジニアの」とあり例示こそエンジニア向けですが、多くの人にとって有用な学習方法のエッセンスが含まれている一冊でした。 書籍を通じて学習に対するモチベーションが生まれたので、モチベーション維持の方法など学んだ知識を取り入れながら積極的に情報収集を行っていきたいと思います。 また、情報収集だけではなく、自身の中に知識を腹落ちさせるモデル化・検証のフェーズも疎かにせず学習に取り組んでいきたいです。 関連リンク エンジニアの知的生産術 著者公式ページ - 西尾泰和のScrapbox 著者による公式ページです。目次や「はじめに」ページを読むことができます。 *1 : 例えば書籍内の「卓越」の話は、「達人 プログラマー 」の「知識の ポートフォリオ 」の話と通じると感じました *2 : 読了後にまとめて書き出したことで忘れてしまった内容もあると感じるため、読みながら感じた点を都度付箋に書き出していけば100枚ほどになるのかもしれません
アバター
こんにちは。新卒1年目エンジニアのrs_shoです。投稿は2回目になります。 今回はGitのブランチの切り替えで失敗したことについて書いていきたいと思います。 はじめに なぜ自動マージが起こったのか 解決方法 stashの戻し方と、それ以外の対処法 おわりに 参考資料 はじめに 前回の記事で commitのタイミングと注意点について の記事を書きましたが、それに少し近い内容です。 別のブランチでコード書いてたけど、元のコードのバグ修正依頼が来たり、レビュー後差戻しがあった場合は、 当然その修正した内容のブランチに切り替えますよね。 その時に元のブランチで書いていた内容が切り替え先のブランチに自動マージされ、余計なファイルとしてstatusに出てきた!なんて経験ありませんか? 僕はそれで色々と困ったので、その時に使った解決策を簡単に説明します。 なぜ自動マージが起こったのか まず、僕が経験した自動マージされてしまった原因ですが、 元のブランチでの作業内容をcommitしていなかった その状態でブランチを切り替えた際に切り替え先でコンフリクトが発生しなかったため、自動マージされてしまった なぜcommitしてなかったかというと、修正途中の段階でcommitしたくなかったからですよ?忘れてませんよ? 僕はその時、なぜマージしてないのに切り替え前のブランチから作業中のファイルがマージされていたのかわからず、困りました。 そして、切り替え先の修正後、元の作業中のブランチに戻ろうとしたらcommitしてくださいと出てしまう。戻れないじゃん・・・ 解決方法 この問題の解決方法ですが、僕は根本的な解決はしてなくて、ちょっと無茶苦茶なことをしているかもしれませんがご了承ください。 僕はそのブランチから自動マージされた内容を消そうかと考えました。 でも切り替え前のブランチから修正内容が消えたらすごく嫌ですよね・・・ commitのタイミングと注意点について で、 機能に関わりのない個人設定のファイル や 間違って編集したファイル は commit対象にするべきではないということを説明しました。 かといってcommitしなきゃブランチ切り替えられないんじゃどうしようもないじゃん! そこで、色々探していった結果、stashコマンドにたどり着きました。 $ git stash これを打つだけ。何をしているのかちょっと説明しますね。 ・コミットはせずに変更を退避したいとき、stashコマンドを使用すると、コミットしていない変更を退避することができる ・退避させていた変更を後で戻して作業を再開することもできる stashはcommitの記録に残るものではなく commitしていない変更内容を退避する コマンドなので、 「変更内容はひとまず置いといて・・・」ができちゃいます。Gitってなんて便利なんだろう。 stashコマンドのおかげで、commitしてくださいと怒られずにブランチ切り替えができました。 stashの戻し方と、それ以外の対処法 僕は心配性なので、変更先で消えるのを怖がっていました。(頑張ったのに消えちゃうとつらい) stashを戻す方法と、それ以外の対処方法を記載します。 まずはstashを戻す方法から。stashって使ったタイミングでcommitみたいに履歴として残ります。 stashした履歴から指定の場所に戻りたい場合は、 $ git stash list stash@{0}: WIP on [ブランチ名]: [HEADのcommitハッシュとcommitメッセージ] stash@{1}: WIP on [ブランチ名]: [HEADのcommitハッシュとcommitメッセージ] で git log のcommit履歴みたいにstashの履歴と大まかな内容が見れます。 そこから番号を指定して $ git stash apply stash@{0} ←0は{ }の番号 これで任意のstashの部分の変更が戻ります。 その他に最新のstashの履歴を戻したい場合には # 最新の退避内容を復元して、退避したデータを消す際(戻した後stashの履歴から削除する) $ git stash pop # 最新の退避内容を復元して、退避したデータを残す際(戻した後stashの履歴から消さずに残す) $ git stash apply stashの番号などを指定しなければ最新が戻ります。 僕は履歴残しても戻したらもう使わないと思ったのでpopを使いました。 最後に、変更自体をなかったことにするコマンドです。僕が使うのを怖がったコマンドです。 別に特殊なことはしませんし、問題が起こることはないと思います。 (何か起きても僕のせいにしないでください) 変更をなかったことにするには # 指定したファイルの変更をなかったことにする $ git checkout [ファイル名] もしくは # statusに出ているすべての変更をなかったことにする $ git checkout . というコマンドです。最近必要ないファイルをadd、commitしないようにするときにも使ってます。 おわりに 以上、ブランチ切り替えで困った際の対処法などをまとめてみました。 自動マージで困った方、編集したファイルの退避の仕方の参考になれば幸いです。 参考資料 git stash で、作業中の変更をいったん横に退けておく 【git stash】コミットはせずに変更を退避したいとき エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
初めまして。今年度新卒入社の mako _makokです。最近実家に帰って水族館でペンギンを見てきました。 今回は 全文検索エンジン のコア機能の一つであるAnalyzerについて書いていきたいと思います。 はじめに 検索エンジンの仕組み Analyzerとは 前準備 Char filter Tokenizer Token filter おわりに はじめに 私は現在、個人的に 全文検索エンジン 学習をしています。 以前までは諸事情で Apache Solrをやっていたのですが、以下の理由からElasticsearchの学習に切り替えました。 シェアとそれに伴うドキュメントの充実 KibanaをはじめとしたElastic Stackの存在 クエリの書き方覚えたらいい感じにクエリ書けそう Apache Solr及びElasticsearchでは Apache Lucene いう OSS の 全文検索 ライブラリがコアになっております。 Lucene には Analyzer という機能があり、 全文検索エンジン において非常に重要な機能です。 今回は実際にElasticsearchでAnalyzerを設定しながら、Analyzerの仕組みを見ていきたいと思います。 検索エンジン の仕組み まずは簡単に 検索エンジン の仕組みを説明します。 検索エンジン ではあらかじめドキュメントのインデックスを作成しておき、そこへクエリが投げられるとそれにマッチするものがヒットするというのが基本になります。 Lucene では 転置インデックス という方式が採用されています。 転置インデックス は以下のような形で作成されます。 転置インデックス 何らかの方法でドキュメントのテキストを分割し、それに対応するドキュメントIDがリストになります クエリが投げられた際も同様、クエリのテキストを分割し、インデックスのキーにマッチした文章が返るという仕組みです。 Analyzerとは 先ほどは 検索エンジン の仕組みについて説明しました。 何らかの方法で分割する とありましたが、この部分がAnalyzerの仕事になります。 正確には、Analyzerは目的のインデックスを作成するために、テキストの分割や正規化などを行います。 Analyzerは以下の3つの機能で構成されています。 Char filter Tokenizer Token filter Analyzerの処理フローです。 Char filter → Tokenizer → Token filterの順に処理されます。 Tokenizerは必須・かつ一つ しか設定できません。 Analyzerの処理手順 前準備 今回はElasticsearchで動作確認を行います。 Analyzerがどのような動きをしているかどうかだけ知りたい方は飛ばしてください。 Java 8以上の環境が必須です。 Elasticsearchをインストール # brew brew install elasticsearch # yum yum install elasticsearch 日本語関連の機能と、テキストの正規化を強化する2つの プラグイン をインストールします analysis-kuromoj analysis- icu cd { ES_HOME } bin/elasticsearch-plugin install analysis-kuromoji bin/elasticsearch-plugin install analysis-icu Elasticsearchを起動して起動確認も行います # 起動 bin/elasticsearch # 起動確認 curl http://localhost:9200/ " name " : " 1GpZYN9 " , " cluster_name " : " elasticsearch " , " cluster_uuid " : " hoge " , " version " : { " number " : " 6.8.3 " , " build_flavor " : " oss " , " build_type " : " tar " , " build_hash " : " 0c48c0e " , " build_date " : " 2019-08-29T19:05:24.312154Z " , " build_snapshot " : false , " lucene_version " : " 7.7.0 " , " minimum_wire_compatibility_version " : " 5.6.0 " , " minimum_index_compatibility_version " : " 5.0.0 " } , " tagline " : " You Know, for Search " } これで準備完了です。これから実際にAnalyzerを作成しながら、Char filter, Tokenizer, Token filterについてそれぞれ解説します。 Char filter Char filterのポイントは以下の通りです。 テキストに対して 機械的 に前処理を行う 必須ではない いくつでも設定できる 機械的 な前処理というのは、例えば文字の全角↔半角処理だったり、 正規表現 による抽出などが挙げられます。 ここからいよいよAnalyzerの設定を行っていきます。 Elasticsearchでは様々な機能が REST API で操作できます。 今回はChar filterに以下を設定します。 icu _normalizer 記号・数字・ 特殊文字 などの正規化を行う kuromoji_iteration_mark 踊り字を正規化 踊り字とは々、ヽ、ゝのような前置の単語によって読み方が変化する単語のことです Analyzerを設定するにはインデックスを保管しておくスペースを作成しなければなりません。 今回はインデックス名を analyzer_handson として、Analyzerを設定していきます。 以下の json をmy_kuromoji_analyzer. json と保存し、POSTします。 { " settings ": { " analysis ": { " analyzer ": { " my_kuromoji_analyzer ": { " type ": " custom ", " char_filter " : [ " icu_normalizer ", " kuromoji_iteration_mark " ] , " tokenizer ": " keyword " } } } } } json を localhost :9200/analyzer_handson/ にPUTします。 curl -XPUT localhost:9200/analyzer_handson/ -H " Content-type: application/json " -d @my_kuromoji_analyzer.json これで my_kuromoji_analyzer というAnalyzerが設定されました。 早速テキストをアナライズしていきます。 ~/_analyze がエンドポイントになっており、こちらで特定のAnalyzerの挙動を確認することができます。 そこに以下の json をPOSTします。 { " analyzer ": " my_kuromoji_analyzer ", " text ": " コウテイペンギンは体格のいいものは130㌢あるという。僕は度々、コンピューターでそれを見て和んでいる " } curl -XPOST localhost:9200/analyzer_handson/_analyze -H " Content-Type: application/json " -d @query.json 以下のような結果が返ってきます。 { " tokens ": [ { " token ":" コウテイペンギンは体格のいいものは130センチあるという。僕は度度、コンピューターでそれを見て和んでいる ", " start_offset ": 0 , " end_offset ": 50 , " type ":" word ", " position ": 0 } ] } 無事正規化されています。 130は全角数字→半角数字 ㌢→センチ 度々→度度 に変換されています。 このような正規化の処理は 自然言語処理 の前処理として非常に重要です。 内部的には半角数字と全角数字などは違う文字として扱われるため、検索のノイズになることや、逆に欲しいドキュメントがヒットしないなどの問題が発生します。 踊り字などは主に古典などでノイズになることが多いです。 他にもChar filterはたくさんあるので、色々試していきたいところです。 Tokenizer Tokenizerはテキストを 分かち書き します。 分かち書き とは、特定の規則に乗っ取ってテキストを分割することです。 ではどのように 分かち書き するのかですが、日本語の場合は 形態素解析 もしくは N-gram を使用することが多いです。 形態素解析 や N-gram のTokenizerには以下のようなものがあります。 kuromoji_tokenizer 日本語用の 形態素解析 器であるKuromojiを使用して 形態素解析 を行う 辞書は2007年からメンテナンスされていないため、新語(芸能人の名前や流行語)などに弱い *1 N-gram Tokenizer 文字数で 機械的 に区切り、 分かち書き を行う 1-gramをuni-gram, 2-gramをbi-gram, 3-gramをtri-gramと呼ぶ 形態素解析 では、テキストを品詞単位で分解し、分割された単語のことを トーク ンと呼びます。 分解した トーク ンには品詞の情報はもちろん、活用形などの情報が付与されます。 Elasticsearchでは Kuromoji という日本語 形態素解析 器が用いられています。 もう一つの 分かち書き の手段の N-gram についてです。 例えばtri-graだとこのように分解されます N-gram 今回はtri-gramなのでテキストを3つに区切りながら一つずつ横にずらしていく感じです。 これら2つの手法はそれぞれ利点・欠点があります 形態素解析 辞書ベースで区切るため、辞書に載っている単語については比較的高い精度の検索結果を得やすい 逆に辞書に載っていない単語などは1文字区切りで 分かち書き されるため、未知の単語に弱い N-gram 機械的 に区切られるため、未知の単語などでもドキュメントをヒットさせることができる "京都で遊ぶ"のような単語で検索されたとき、上記の画像のように"東京都"を含むドキュメントがヒットする 検索ノイズが増えやすい どちらも一長一短なので、検索要件によって適切にTokenizerを設定する必要があります。 今回は 形態素解析 を用いて単語分割していきたいと思います。 Analyzerの設定を更新するために、まずは一旦インデックスをcloseします。 curl -XPOST localhost:9200/analyzer_handson/_close 次に、Char filterの時に使用したmy_kuromoji_analyzer. json のtokenizerを kuromoji_tokenizer に編集しPOSTします。 { " settings ": { " analysis ": { " analyzer ": { " my_kuromoji_analyzer ": { " type ": " custom ", " char_filter " : [ " icu_normalizer ", " kuromoji_iteration_mark " ] , " tokenizer ": " kuromoji_tokenizer " } } } } } # 更新する際は/_settingsにPOSTします curl -XPUT localhost:9200/analyzer_handson/_settings -H " Content-type: application/json " -d @my_kuromoji_analyzer.json 最後にopenして完成です curl -XPOST localhost:9200/analyzer_handson/_open 早速テキストを投げてみると以下のように 形態素解析 されていることがわかります。 { " tokens ": [ { " token ":" コウテイペンギン ", " start_offset ": 0 , " end_offset ": 8 , " type ":" word ", " position ": 0 } , { " token ":" は ", " start_offset ": 8 , " end_offset ": 9 , " type ":" word ", " position ": 1 } , { " token ":" 体格 ", " start_offset ": 9 , " end_offset ": 11 , " type ":" word ", " position ": 2 } , ... ~ ... { " token ":" 和ん ", " start_offset ": 45 , " end_offset ": 47 , " type ":" word ", " position ": 21 } , { " token ":" で ", " start_offset ": 47 , " end_offset ": 48 , " type ":" word ", " position ": 22 } , { " token ":" いる ", " start_offset ": 48 , " end_offset ": 50 , " type ":" word ", " position ": 23 } ] } 無事Kuromojiを使用して 分かち書き をすることができました。 最後はToken filterです。 Token filter Token filterではTokenizerで 分かち書き された トーク ンに対して様々な変換処理を行います。 以下はToken filterの一例です。 Lower case Token filter トーク ンを全て小文字に変換する Stop Token filter ストップワード の除去を行う ストップワード とは、 自然言語処理 において、一般的であるなどの不要な単語のこと Stemer Token filter 語幹ごとに定義されたステミング処理を行う ステミングとは語形の変化をなくし、表現を統一すること Synonym Token filter 類義語の展開を行う 表記揺れ(引越し、引っ越し、引越)や類義語(パソコン、PC、コンピュータ)など Kuromoji-Analysisに付属しているToken FIlter kuromoji_baseform 動詞・形容詞を原型に戻します。活用形は表記揺れの原因になります。 kuromoji_part_of_speech 特定の品詞を削除します。検索において、助詞や助動詞などは必要でないケースがあります。 デフォルトでは {助詞-格助詞-一般, 助詞-終助詞}を削除します。 形態素解析 を行うことによって、単語に品詞情報が付与されます kuromoji_stemmer 日本語に特化したステミング処理用のToken filter。カタカナの伸ばし棒を削除します。 今回は上記の KuromojiのToken filter 3種と、 Synonym Token filter , Stop Token filter を使用していきます " コウテイペンギン "で一単語であり、"ペンギン"で検索した時にヒットしない 二つの単語を一つのシノニムグループ *2 として扱うmy_synonym_penguin_filterを新しく作成し、filterに追加 動詞や形容詞であるが、いい、もの、ある、いるなど様々な文章で頻出しそう。文章の特徴を表さないのでなくても構わなそうな単語がある *3 頻出しそうな単語をstopwordsに追加 { " settings ": { " analysis ": { " analyzer ": { " my_kuromoji_analyzer ": { " type ": " custom ", " char_filter " : [ " icu_normalizer ", " kuromoji_iteration_mark " ] , " tokenizer ": " kuromoji_tokenizer ", " filter ": [ " kuromoji_baseform ", " kuromoji_part_of_speech ", " kuromoji_stemmer ", " my_synonym_penguin_filter ", " my_stop_filter " ] } } , " filter ": { " my_synonym_penguin_filter ": { " type ": " synonym ", " synonyms ": [ " コウテイペンギン,ペンギン " ] } , " my_stop_filter ": { " type ": " stop ", " stopwords ": [ " いい ", " もの ", " ある ", " いう ", " それ ", " いる " ] } } } } } 設定を適用したら同じクエリを投げていきます。 すると以下のような結果になりました。 { " tokens ": [ { " token ":" コウテイペンギン ", " start_offset ": 0 , " end_offset ": 8 , " type ":" word ", " position ": 0 } , { " token ":" ペンギン ", " start_offset ": 0 , " end_offset ": 8 , " type ":" SYNONYM ", " position ": 0 } , { " token ":" 体格 ", " start_offset ": 9 , " end_offset ": 11 , " type ":" word ", " position ": 2 } , { " token ":" 130 ", " start_offset ": 17 , " end_offset ": 20 , " type ":" word ", " position ": 7 } , { " token ":" センチ ", " start_offset ": 20 , " end_offset ": 21 , " type ":" word ", " position ": 8 } , { " token ":" 僕 ", " start_offset ": 27 , " end_offset ": 28 , " type ":" word ", " position ": 12 } , { " token ":" 度度 ", " start_offset ": 29 , " end_offset ": 31 , " type ":" word ", " position ": 14 } , { " token ":" コンピュータ ", " start_offset ": 32 , " end_offset ": 39 , " type ":" word ", " position ": 15 } , { " token ":" 見る ", " start_offset ": 43 , " end_offset ": 44 , " type ":" word ", " position ": 19 } , { " token ":" 和む ", " start_offset ": 45 , " end_offset ": 47 , " type ":" word ", " position ": 21 } ] } しっかり設定したToken filterの効果が表れています kuromoji_baseform(原型へ変換) 見て→見る 和ん→和む kuromoji_part_of_speech(助詞-格助詞-一般, 助詞-終助詞の削除) コウテイペンギン "は" 、コンピューター"で"などが削除されています kuromoji_stemmer(語幹の統一) コンピューター→コンピュータのように伸ばし棒が除去されています Synonym Token filter コウテイペンギン が コウテイペンギン とペンギンの二語に展開されています Stop Token filter 設定した"いい", "もの", "ある", "いう", "それ", "いる"がそれぞれ除去されています。 おわりに 実際にAnalyzerを設定してみました。 Analyzerだけではなく、他にも様々な機能がElasticsearchにはあります。 次は検索ネタを話せたらと思います。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com *1 : MeCab 用の新語対応辞書 mecab -ipadic-neologdを適用した、Kuromojiの プラグイン があります *2 : 双方向展開 *3 : 実際に使用する際は公開されている ストップワード リストをメンテナンスするのが良い
アバター
こんにちは!新卒のrs_chankoです。 エンジニアとして就職して早半年になります。 大学でもプログラミングを学んだものの、チーム開発は初めて。 就職してから「 バージョン管理システム 」というものに触れました。 とても便利ですよね。 しかしその反面、難しい。 僕が最初にハマった落とし穴。 「git rebase」 です。 間違えて必要のないファイルをpushしちゃった!ってことありませんか? ありますよね?僕はあります。 玄人の皆さんには簡単なことかもしれませんが、 初心者の僕は解釈違いで落とし穴に…。 自分の失敗を繰り返さないよう、超初心者 僕も含め の皆さんにイメージをつかんでもらえたらなと。 ということで、今回は詳しい使い方というより Gitに慣れていない方へ向けイメージをつかみやすいように 僕なりに解釈した「commitを取消すコマンド」についてたとえ話を交えて書いていきたいと思います。 間違えていないといいな イメージをつかむ git reset git revert git rebase おわりに イメージをつかむ プログラマー に必須の力に「想像力」があります。(持論) それぞれどんな挙動を起こすのか。それが想像できないと痛い目を見ます 僕がそうです そしてGItでcommitを取消す方法もいくつかあります。 それぞれ似ているようで少し動きが違うようで。 ここでは3種類のコマンドを紹介したいと思います。 それぞれ「 ハッシュ値 」を、「夏休みの宿題の日記の日付○月×日」としてたとえ話にしています。 git reset イメージとしては 「日記のページを特定の日まで破り捨てる」 感じですかね。 例えば $ git reset --soft [ハッシュ値] このコマンドをたたくと、現時点から、○月×日の翌日までの日記を破り、○月×日の次から今日のことを書く感覚です。 resetのイメージ図 破ったページは捨てずに置いてあるので、戻すことも可能です。 しかし、机の中にしまっておくので、先生(共同作業者)には見られません。(画像ではC~Fがしまってあるような感じ、) ただし「特定の1つのコミット」を消すわけでなく、 「特定のコミットまですべてのコミット」を消すことになるので、注意が必要です。 (作業状態はオプション次第で残せる) git revert こちらは 「日記の特定の日を破り捨て、破り捨てたことを報告するページを一番新しいページに貼り付ける」 といった感じでしょうか。 「日記でそんなこと絶対やらないよ!」とは思いますが… $ git revert [ハッシュ値] このコマンドで○月×日のページを破り捨て、 新たに「○月×日のページ破り捨てたよ~」と最新のページの次のページに付け足します。 先生に怒られそうですね。 revertのイメージ図 しかし、チーム開発では何を削除したのか、これが重要になると思いますので、 とても便利ですね。 (僕はこれを使いたかった) git rebase こちらは 「日記の特定の日を破り捨てて、その日から書き直す」 といった感じ。 どういうこっちゃといった感じですが。 こちら、厄介なことに「HEAD」が移動するのです。 $ git rebase -i [ハッシュ値] こちらをたたくとviに ハッシュ値 以降のコミットが表示され、 各コミットのコマンドを編集することで作業ができます。 例えば○月×日の次の日を削除します。 すると、突如タイムスリップします。(本当に唐突ですがこれがHEADが移動したというやつ) ○月×日の次の日から日記を書くことになるのですが、夏休み最終日、 何故かもう一冊の日記(タイムスリップする前のもの)が存在するのです。 どっちが本物だ、、、となるため、競合が発生します。 rebaseのイメージ図 こんな感じのことが起きています。削除したコミットよりもあとを編集してpushしようとすると コンフリクトが大量発生… 僕はこれで痛い目を見ました。 おわりに そんなこんなでイメージはつかめたでしょうか。 自分の実現したい挙動をするコマンドを探すために 「想像力」が大切。(だと思います) commitを取消するのには気を付けようという話でした。 実践編はまた後日! エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 forms.gle イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! rakus.connpass.com
アバター
はじめに ラク スに入社して1年のitoken1013です。 ラク ス入社前まで SIer でPM補佐やPMOを経験してきましたが、 この度あらためてプロジェクトマネジメントについて学ぶ機会がありました。 そこで今回は PMBOK を用いて、プロジェクトマネジメントの基礎知識についてご紹介したいと思います。 これからPMを目指す方や、ベテランの方の復習にお役立ていただけますと幸いです。 PMBOK とは PMBOK (Project Management Body Of Knowledge)は アメリ カの 非営利団体 「PMI」が定めた、プロジェクトマネジメントに関する知識体系です。 不確実要素が多いプロジェクトを成功させるために、必要とされる知識を体系的に定めています。 IT業界以外でも PMBOK は活用されており、組織全体におけるプロジェクト管理標準のベースとして PMBOK を採用している企業もあります。 プロセス群・プロセス 最新となる第6版の PMBOK では、プロジェクトの実施に必要な計49種類のプロセスを定めています。 またそれらをプロジェクトのライフサイクルに則した下記5つのプロセス群に分類しています。 すべてのプロセスをご紹介することはできませんが、プロセス群の紹介と共に代表例を挙げていきたいと思います。 普段何らかのプロジェクトに属しながら仕事をされている方であれば、 ご自身の業務に当てはめてイメージいただければ分かりやすいかと思います。 1. 立ち上げプロセス群 対象となるプロジェクトまたはフェーズを定義した上で、関係者から認可を得るためのプロセスです。 認可を得るためには対象となるプロジェクトの目的やスコープを明確化する必要があり、プロセスには「プロジェクト憲章作成」と「 ステークホルダー 特定」の2つが含まれます。 2. 計画プロセス群 プロジェクトでの目標を達成するための計画を具体化するためのプロセス群です。 「プロジェクト計画書作成」「コスト見積もり」「 WBS 作成」など計20プロセスが属します。 3. 実行プロセス群 計画プロセス群で定めた計画に則り、作業を完了させるためのプロセス群です。 プロジェクトチーム内に対するプロセスである「チームの育成」や「品質のマネジメント」の他、 「 ステークホルダー ・エンゲージメント・マネジメント」などチーム外の関係者を含めたプロセスが定義されています。 4. 終結 プロセス群 「プロジェクトやフェーズの 終結 」プロセスが示す通り、プロジェクトを公式に終了するためのプロセス群です。 またプロジェクトで得た教訓(Lessons Learned)を組織の資産として蓄積し、次のプロジェクトの品質向上に役立てていくことが PMBOK では重要視されています。 5. 監視・コン トロール プロセス群 プロジェクト計画通りに上記1~4のプロセス群が進捗するようにコン トロール するためのプロセス群です。 「プロジェクト作業の監視・コン トロール 」「統合変更管理」等のプロセスによって、プロジェクト計画との差異の識別・是正を行います。 プロジェクトマネジメント知識エリア 次にご紹介するのは、各プロセスの実施に必要となる知識をカテゴライズした10種類の知識エリアです。 プロジェクトを円滑に進めるために、マネジメントをすべき分野と言い換えてもよいでしょう。 統合マネジメント スコープマネジメント スケジュールマネジメント コストマネジメント 品質マネジメント 資源マネジメント コミュニケーションマネジメント リスクマネジメント 調達マネジメント ステークホルダー マネジメント 経験上、特に重視しなければならないと考えているのは リスクマネジメント と ステークホルダーマネジメント です。 リスクマネジメントは将来に起こるかもしれないリスクを取り扱い、 ステークホルダー マネジメントは「プロジェクトに反対する人」も含む関係者との関わりを取り扱います。 どちらにも共通する点として自分達からは見えづらい側面、つまり 不確実性 が伴うため、コン トロール が特に難しいマネジメント領域として考えられます。 これらは エンジニアリング組織論への招待 でいうところの 環境不確実性 (未来)と 通信不確実性 (他人)の要素を含んでおり、書籍で触れられているような不確実性に向き合うための思考力と行動力が必要となります。 PMBOK を学ぶことで役立ったこと 断片的にしか理解できていなかったプロジェクトマネジメント知識を体系化できた他、私が PMBOK を学んで日々の仕事に役立っていることは主に3点です。 1. 計画作業の標準化 プロジェクト全体のマネジメントに限らず、特定のフェーズの計画や管理にも PMBOK の知識は有効であると感じています。 ラク スで私が 結合テスト の計画書作成を任された際には、テストを円滑に進めるために必要となる要素を洗い出す際に PMBOK を参考にして構成を練っていました。 計画作業の標準化や客観的に計画を捉える視点を養うためにも、 PMBOK の理解は有効です。 2. プロジェクトの共通認識 体系化されたマネジメント知識をチームメンバー全員がインプットできていると、全員が同じ共通認識のもとでプロジェクトを円滑に進めることができます。 特に多くの ステークホルダー が関わるプロジェクトの場合には、孤独なマネージャーを近い目線で助けられるメンバーはとても重宝されます。 またマネージャー視点からは見えにくいリスクを提起できるメンバーも、計画通りにプロジェクトを進行するために貴重な人材かと思います。 3. 個人タスクへの応用 自身が担当しているタスクの遂行にも、 PMBOK の知識は応用できると考えています。 タスクの前後で関わる人と適切なタイミングでコミュニケーションをとれる、事前に関係者へリスクを共有できる等ができると、円滑に仕事を進められる確率が上がるためです。 コミュニケーションマネジメントや ステークホルダー マネジメントのエッセンスから学べる点は多いかと思います。 ちなみに ラク スの社員はお互いの仕事の影響を考えて動いてもらえる方が多く、エンジニアに限らず、どの社員ともとても仕事を進めやすいと感じています。 まとめ PMBOK をもとにプロジェクトマネジメント知識をご紹介してきました。 実際のプロジェクトでは特有の業務知識や技術知識、現場での経験や勘が要求されるため、これさえ抑えればプロジェクトは成功!とはいかないケースがほとんどのはずです。 ですがプロジェクト実施中に何らかの問題が発生した際、闇雲に解決策を探るのではなく、ベストプ ラク ティスを凝縮した PMBOK を活用することで成功の確率を上げることはできるのではないかと思います。 PMBOK にご興味がある方がいましたら、より詳細な関連書籍を読み進めていただければと思います。 ブログをお読み下さり、ありがとうございました。
アバター
はじめに こんにちは、 @rs_tukki です。上半期も終わったところでこの六ヶ月のうちに書いた言語を数えてみたところ、実に7つもの言語を触っていたことに気づき驚いています。 さて、先日コードを書いているうちに以下のようなことが必要になりました。 「Web上でファイルを選択したと同時に、そのファイルデータをサーバ上で処理させる」 色々実現方法を考えていたのですが、今回はそのための方法として Ajax に触れたのでご紹介します。 はじめに Ajaxとは ファイル選択時に起動するjavascript ファイルをバイナリデータにして送信してみる まとめ 参考 Ajax とは 困ったときの Wikipedia 先生。 Ajax - Wikipedia Ajax (エイジャックス[1][2]、 アジャックス [3])は、ウェブブラウザ内で非同期通信を行いながら インターフェイス の構築を行うプログラミング手法である[4]。 XMLHttpRequest (HTTP通信を行うための JavaScript 組み込みクラス)による非同期通信を利用し、通信結果に応じてダイナミックHTML (DHTML) で動的にページの一部を書き換えるというアプローチを取る[5]。 Ajax とは、 A synchronous Ja vaScript + X MLの略語で、 JavaScript の組み込みクラスを使用することで、ページ遷移をすることなく非同期にサーバとやりとりしたり、ページを書き換えたりする手法を指します。 例えば、入力フォームで郵便番号を入力したとき、自動的にその番号に対応する住所を入力してくれる…といったシステムも Ajax を使っていることが多いです。 ファイル選択時に起動する javascript さて、今回は Jquery を使って ajax によるサーバ通信を行い、ファイル選択と同時にそのファイルデータをサーバに送ってみます。 まずはHTML側から。 file.html < html > : (中略) : < input type = "file" name = "file" onchange="file.fileAttach ( this ) ; return false ;" /> : (中略) : </ html > input type="file" は下記のように、何らかのファイルを選択できる入力フォームです。 これに onchange 属性を組み合わせることで、フォームの中身が変わったとき、つまりファイルが選択された時に任意の javascript 関数を実行させることができます。 ファイルをバイナリデータにして送信してみる 続いて、今回の肝となる javascript の中身を見てみます。 今回、 Ajax の実現には Jquery の ajax メソッドを使用しました。 file.js fileAttach: function (inputFile) { var file = inputFile.files [ 0 ] ; //ファイルデータを取得 var url = 'https://hogehoge.co.jp' ; //リクエスト先を指定 var reader = new FileReader(); var formData = null ; reader.onload = function () { formData = reader.result; } reader.readAsBinaryString(file); setTimeout(() => { $.ajax( { url: url, cache: false , //キャッシュを使用しない type: "POST" , data: { "formData" : formData, } , } ).done( function (data) { //成功時 console.log( "success" ); } ).fail( function () { //失敗時 console.log( "failed" ); } ); } , 500); //少し待ってから実行する } , 発火元の入力フォームからファイルを取得してきて、それをバイナリデータに変換しています。 FileReader は javascript でファイルデータを扱うためのオブジェクトで、今回はonload=読み込みが完了したタイミングでバイナリ文字列を取得しています。 そのデータをパラメータに格納して Ajax 通信を行うことで、 画面遷移させることなくデータをサーバに送信することが出来ます。 実際に試してみると、サーバ側で以下のようにバイナリ文字列を取得できていることが分かるかと思います。 あとはこれをbyte型に変換してやればOKです。 まとめ 今回は、画面遷移をすることなくサーバへバイナリデータを送信する方法について説明しました。 自分でもまだ勉強が足りないため、もう少し綺麗な方法がある気がしますが…それはまた機会があれば。 参考 Ajax - Wikipedia $.ajax() | jQuery 1.9 日本語リファレンス | js STUDIO FileReader.readAsBinaryString() - バイナリ文字列として読み込む | File APIリファレンス エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 forms.gle イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! rakus.connpass.com
アバター
はじめに 性能 回帰テスト を自動化するプロジェクトを開発をしながら隙間を見つけてチームメンバーと行なっておりました。 完成して運用している今、下記3つをポイントに紹介していきたいと思います。 どのようにプロジェクトを進めたのか 進める上でどのような課題が出て解決したのか 運用方法 昨年の弊社 アドベントカレンダー ( 性能回帰テストの自動化プロジェクト始めました )にてプロジェクトの進め方を紹介しました。 そこから再編集を行い、この記事にて完結編とさせていただきます。 自動化と言う前にやったこと 自動化!! すごく楽になるそんな夢のような仕組み。 自動化する目的は?自動化して得られる効果は?手段が目的になっていませんか? 技術というのは課題、問題を解決する手段の一つです。 自動化すると言って手を動かす前に、目的を整理する。 自分やプロジェクトが抱えてる課題は本当に自動化で解消、緩和されますか? 漠然と自動化すればなんとかなると考えていないですか? 整理した後、フィードバックをオススメします。 目的、手段、背景・課題、効果 この観点で概要をまとめました。 ■ 概要説明 ■ <目的> テストコストの抑制/削減を行う <手段> ・ CI環境に組み込みテスト実行と結果出力を自動化する ・ JMeterでテストシナリオを実行し、レスポンスタイムを計測する <背景・課題> 性能改善を実施したが新機能追加、改修を続けながら性能を維持する必要がある。 しかし、そのためには機能開発毎にテストが必須となり、テストコストの増加が予測できる。 <効果> 毎日自動でテスト実行することで以下のような効果が得られる ・ 自動化することにより、性能劣化を担保するテストコストを削減することができる。 ・ 毎日テストを実行することで、性能劣化の早期発見、早期対応が可能となり、   アプリケーションの保守コストを最小限に抑えることができる。 現状把握 目的地までの道順を確認する時、自分の現在地がわからないと道順も出てきません。 日常生活の中で何気なくやってる思考が仕事でも十分役立ちます。 CIに組み込むと意気込んだものの、今動いてる環境の構成図ありませんでした。先輩から後輩と一緒レクチャーを受け後輩に構成図を描いてもらいました。 既存の構成図に新しく構築したいものを組み込んで完成!ドキュメント作成はメンバーと認識を共有するするためのものです。毛嫌いする人もいますが、コミュニケーションをとる手段の1つではないでしょうか。 青線が静的解析のフローで、オレンジ線が今回追加しようと動いている性能 回帰テスト のフローになります。 どんなテストフローにするのか 人の手でやっているテストを実行するまでの段取りを書き出してみました。 基本的に人が手でやってたことを自動にすることが自動化だと私は理解しています。 いつ(何時から)どんなデータでどのようなテストを行う? 描いたシナリオ テストデータは毎日作って破棄 全画面のレスポンスを測定するテストシナリオ 0時からテスト開始、8時には完了 レスポンスタイム結果を出力 まず、 1.テストデータは毎日作って破棄 日々新規開発は続いているので、それに合わせると毎日テストデータは作る方がメンテコストが抑えられる。 2.全画面のレスポンスを測定するテストシナリオ せっかくの自動化なのでテストできるものは全部組み込んでしまおう。 3.0時からテスト開始、8時には完了 弊社の始業時間は9時なので、1時間前までには終わればいいかな程度。8時間あれば終わるでしょうという考え。 4.レスポンスタイム結果を出力 とりあえず出力結果を CSV で出力、レスポンスタイムの平均値とか スループット の表を出力します。可視化もしたいが、まずは結果を出力するまでを行う。 案外ざっくり決めです。 実際にシナリオ流してみた 試しに流してみると、テストデータを作るのに4〜5時間。全画面のテストの3割を流すのに3時間はかかってしまうことがわかったのです。3割で3時間。 このままでは、 全画面テストは想定している時間内で実行できない可能性が高い テストデータの作成に想定していたより時間がかかる ということに気づきました。 考えていたストーリーが本当に実現できるのか? というのを早めに試作して検証することをオススメします。 新規機能の開発も同じですが、想定外なことが起こることは早めに気づくと リカバリ という手段が見いだせます。 課題と課題解決 テストデータの作成に想定していたより時間がかかる テスト数全体の3割で3時間の実行時間がかかる テストシナリオの管理、メンテナンスどうするか 日々の結果はどうやって確認するのか テストデータの作成に想定していたより時間がかかる テストデータを毎度作成するには不安定であることと、テスト時間に収めるためにあらかじめデータを入れたdumpファイルを作成し、それをrestoreすることにした テスト数全体の3割で3時間の実行時間がかかる そもそも全画面のテストを流す必要はあるのだろうか? テストの目的を考え抜いた結果、 テストで最も品質を担保したい画面を選抜することにした。 その結果、テストデータ作成からテスト実行からテスト結果の出力まで、当初考えていた8時までに収めることができた テストシナリオの管理、メンテナンスどうするか テストシナリオは資産である ソースコード と同じで、Gitに新しくシナリオ管理用のプロジェクトを作りバージョン管理 メンテナンスもバージョンごとに必要であれば行い、バージョンごとにタグを打ち、それをメンテナンス完了している印とした 日々の結果はどうやって確認するのか テスト結果は csv で出力する 性能劣化が誰が見ても一目でわかるように、横軸を日付、縦軸をレスポンスタイムにして、折れ線グラフで可視化した テスト結果はデータベースに管理 パーティショニングを使ったテーブル構成 redashというツールを使いテーブルからデータを読み込んでグラフにする ここまで考えたのですが、タイムアップにより csv を VBA に読み込ませグラフ化するシェルを手動実行 に留まっており、可視化した結果をチームの 有識者 が日々確認しています。 運用スケジュール 月曜日から金曜日の深夜12時半から性能 回帰テスト を実行、朝8時半には完了 土曜日のみ昼12時半から負荷テストを実行、13時半には完了 実は、負荷テストのjobがすでに存在していたため、これを機にCIに組み込み、バージョン管理も始めました。 テストシナリオ、テストデータの配置 サーバーに手動で配置 変更することがほとんどないため固定とした テストがあることのメリット 性能改善を行った時のテストが楽 日々の結果をグラフにしているので、改善したコードをmasterにマージした翌日から、改善できたことが一目でわかる 正常系のシナリオを作っているので、性能改善以外にも デグレ していないかの担保にもなる サーバーやOSのリプレイス、MWのメジャーバージョンアップをした時のテストに使える バージョンを上げる前のデータを取り直す必要もなく、比較ができるためわざわざテストを組む必要がない JenkinsのJobを作って退勤時にボタンをポチッとするだけで、翌朝にはテストが終わって業務時間を有効に使うことができる 人がテストをする必要がなく、より創造的なことに時間を使うことができます。 最後に 『まずは価値を届ける』 を軸にこの改善プロジェクトを進めました。 テストがあることのメリット は、実際に運用を始めた後に実務で活用した事例です。 タイムアップして手動にとどまった点もありますが、手動の部分があっても十分に性能 回帰テスト の価値を届けられています。むしろプラスαで活用できています。 今後、手動部分を自動にして少しでも手がかからないようにしていきたいです。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 forms.gle イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! rakus.connpass.com
アバター
こんにちは、株式会社 ラク スで横断的にITエンジニアの育成や、技術推進、採用促進などを行っている開発管理課に所属している鈴木( @moomooya )です。 前回は匿名化したデータがどの程度匿名化されているかの指標についてお話ししました。 tech-blog.rakus.co.jp 今回は今回の取り組みの中で実際にデータを匿名加工する際にどのような流れで進めたのかについてお話ししていこうと思います。 連載目次 『全文検索 〜 Elasticsearchとデータ匿名化手法』 『全文検索の探求 Elasticsearch(1) 』: プロジェクト方針およびElasticsearch概要 大量データを検索するサービスでElasticsearchはRDBの代替候補になりうるか?(Elasticsearch vs pg_bigm)』 データ匿名化 第1回:匿名化された個人情報とは何なのか データ匿名化 第2回:個人情報は匿名化しても意味がないのではないか? データ匿名化 第3回:個人情報を匿名化するプロセス データ匿名化 第4回:匿名化のために行うデータ項目の一般化とは データ匿名化 第5回:データ匿名化の指標 データ匿名化 第6回:実際の匿名化 ←今読んでいる記事 匿名加工処理の流れ 実際のデータ匿名化の流れは以下のようになります。 利用用途の定義 対象デー タセット の選定 対象デー タセット における識別子、準識別子、機密属性の定義 デー タセット の加工 ツールによる評価 状況によっては多少順序が前後する工程もありそうですが、だいたいはこの流れで問題ないと思います。 それでは1つずつ見ていきたいと思います。 1. 利用用途の定義 まずは匿名加工したデータをどのような目的で利用するかを定義します。 データの匿名化作業に慣れている場合には問題ないのかもしれませんが、以降の工程でどの項目が準識別子なのか、どの項目が機密属性なのか、どの項目をどの程度一般化して問題ないのか、という判断をする際に目的を明確にしておかないと「この項目を一般化するのが一般的」という感覚に引きずられて遠回りをしがちです。 例えば今回のような検索性能の検証データとしてデー タセット を匿名化していく場合にも、主な検索項目が 自然言語 によるフリーテキストなのか、数値項目なのか、日付項目なのか、によってもどの項目をどの程度一般化するのか、という判断が変わってきます。 2. 対象デー タセット の選定 対象のデー タセット は社内で開発しているサービスのデー タセット であれば比較的容易に定まるのではないでしょうか。 この際できるだけ実際に運用しているリアルなデー タセット を採用する方が良いでしょう。データ定義を元に作成したサンプルデータだとどうしてもデータ作成者によるバイアスがかかってしまい理想のデー タセット になってしまいがちです。 社内で ドッグフーディング している環境があれば理想的だと思いますが、目的が「特定の顧客で発生している性能問題の原因特定」みたいな場合は顧客担当者に交渉してデータを利用させてもらうなどの手順を踏まなければならないでしょう。 3. 対象デー タセット における識別子、準識別子、機密属性の定義 対象となるデー タセット が決まったら識別子、準識別子、機密属性の定義です。 tech-blog.rakus.co.jp 識別子は用途に左右されずに比較的 機械的 に定義できると思います。準識別子デー タセット に依存する部分はありますが、頻繁に扱われるであろう住所、年齢、性別などは準識別子となるでしょう。 機密属性(漏洩すると問題になる項目)はデー タセット によりけりなので都度判断が必要になってくると思います。 4. デー タセット の加工 識別子、準識別子、機密属性が決まったらデータを加工していけます。 識別子の削除 識別子は無条件で削除されます。 準識別子の加工 準識別子については秘匿すると情報量が大きく減ってしまうため、できるだけ秘匿しないよう一般化していきます。 匿名化後のデー タセット の用途を考慮して、準識別子の項目を一般化していきます。 以下の記事のように準識別子をそのままにしてしまうと高い確率で特定されてしまうので何らかの加工を加えると良いと思います。 jp.techcrunch.com 具体的な加工方法については第4回の記事で解説しています。 tech-blog.rakus.co.jp 5. ツールによる評価 実際のデー タセット に含まれるレコード数は少なくとも数万件以上あると思いますので手動で評価を行うことは非現実的だと思いますので、ARXといった匿名加工ツールを利用します。 arx.deidentifier.org 前回説明させていただいたk-匿名性、l-多様性というプライバシーモデルについてもこちらのツールで設定することができます。 tech-blog.rakus.co.jp ARXの概要 ARXはデータ匿名化に関する包括的な オープンソース ソフトウェアです。 指定した入力データソースを対象に 各種プライバシーモデルを設定し デー タセット の変換や デー タセット の評価 を行うことができます。今回は変換には利用せず、デー タセット の評価にのみ利用しました。 Java 製のアプリケーションなので Windows / macOS / Linux 問わず利用することができます。 ARXの基本的な設定方法 インストールを終えて起動したらデータを読み込みます。 CSV データを入力するケースを例にします。 CSV ファイルを読み込む もしくはメニューから [File] > [Import data...] を選択。 ※このとき読み込み済みのデータと設定はリセットされるため注意。 各カラムの識別子区分を設定する 各カラムに識別子区分を設定していく。 識別子区分は以下の通り。 非機密属性: Insensitive 機密属性: Sensitive 準識別子: Quasi-idepntifying 識別子: Identifying 評価指標を設定する k-多様性を追加する場合は k-Anonymity を選択してkの値を設定して OK をクリック。 評価結果を確認する 攻撃モデル 3種類の攻撃モデルに対する特定確率という形式で評価されます。 Prosecutor attacker model / 検察官攻撃者モデル(検察官リスク) 特定の人を特定することを目的とした攻撃 匿名化されたデー タセット 内に存在することがわかっている個人に対して、匿名化されたデー タセット 内の情報を利用して特定を試みる Journalist attacker model / ジャーナリスト攻撃者モデル(ジャーナリストリスク) 特定の人を特定することを目的とした攻撃 匿名化されたデー タセット 内に存在することがわかっている個人に対して、公開されている別の情報ソースを利用して特定を試みる Marketer attacker model / マーケッター攻撃者モデル(マーケッターリスク) 不特定多数を特定することを目的とした攻撃 特定結果の一部が誤っていることを問題としない 検察官リスク、ジャーナリストリスクは必ずマーケッターリスクと同等もしくはそれ以上になる 評価値 Records at risk 閾値 を超えるリスクを伴うレコードの割合 Highest risk 単一レコードでもっとも高いリスク(特定可能性) k=2 であれば多分50%になる Success rate 平均再特定リスク Risk thresholds リスク 閾値 Highest risk Records at risk を算出するための 閾値 この値を超えるレコードの比率が Highest risk となる これらの指標値を元にプロジェクトごとに設定した 閾値 をパスするようデータを加工します。当然1度の加工でパスしない場合は一般化の度合いを調整するなどして試行錯誤が必要になります。 参考:今回の取り組みでの目標 閾値 今回の取り組みでは以下4点を満たす場合に 匿名化されている と設定してデータ加工を行ないました。ご参考になれば。 Risk thresholds / Main - Highest risk 50%以下 Records at risk(%) 0% Highest risk(%) 1%以下 Success rate(%) 1%以下 まとめ 今回は実際のデータをどのように匿名化していくのかについてお話ししました。 本連載はこれで終わりとなります。 今回の取り組みではElasticsearchとデータ匿名化手法をテーマにし、主にデータ匿名化についての調査、検証を進めていました。 今まではデータの匿名化というものについてなんとなくではわかっているものの、どういうアプローチが確立されていて、どういう評価をすれば良いのかはわかっていませんでしたが、本連載でまとめた内容を理解することでだいぶ理解が進められたと思います。 少し前にTechCrunchで以下のような記事が公開され話題になっていましたが、今であれば「一般化もしない準識別子を残していれば特定できるのは当たり前」だと冷静に読み解くことができるようになりました。 jp.techcrunch.com 今後、業務で機密属性を含むデータを取扱うことになった場合にもさらに安全に安心してデータを取扱っていけると思います。 かみせんプロジェクトでは今後もテーマを設定して検証を進めていきます。 次のテーマが決まり、検証が進んだらまたレポートを公開していきたいと思いますのでよろしくお願いします。 連載目次 『全文検索 〜 Elasticsearchとデータ匿名化手法』 『全文検索の探求 Elasticsearch(1) 』: プロジェクト方針およびElasticsearch概要 大量データを検索するサービスでElasticsearchはRDBの代替候補になりうるか?(Elasticsearch vs pg_bigm)』 データ匿名化 第1回:匿名化された個人情報とは何なのか データ匿名化 第2回:個人情報は匿名化しても意味がないのではないか? データ匿名化 第3回:個人情報を匿名化するプロセス データ匿名化 第4回:匿名化のために行うデータ項目の一般化とは データ匿名化 第5回:データ匿名化の指標 データ匿名化 第6回:実際の匿名化 ←今読んでいる記事
アバター
初めまして。新卒1年目エンジニアのrs_shoです。 今回はGitのcommitタイミングと注意点について書いていきたいと思います。 はじめに そもそもcommitって? commitのタイミング commitする際の注意点 おわりに 参考資料 はじめに 皆さん、 バージョン管理システム のGit、使ったことありますか? 僕は、社会人になって初めて「 バージョン管理システム 」を使いました。かなり便利ですね! 過去のある状態に戻したり、元のファイルを編集しないようにブランチを切って編集後に差分を反映したり・・・ 学生時代から使っておきたかった、なんで使ってないんだ!過去の自分よ・・・と思うくらい便利です。 そもそもcommitって? 「commitってなんだ」と思う方もいるかもしれないので、つかみ程度に・・・ ・Gitで「追加編集したファイルを登録するコマンド」のこと ・編集した履歴、差分などが記録される ・commitしたポイントに戻ることができる 3つ目が個人的にかなり便利だと思います。 具体的にはcommitする前にファイルをaddするなんてことも必要ですが、今回説明は割愛します。 commitのタイミング ではそろそろ本題へ・・・ commitって便利ですが、「いつすればいいの?」っていう人多いんじゃないでしょうか。 僕がGitを使って間もない頃、 commitをし忘れ たり、 あまり意味のないタイミングでcommit して、 一緒に研修していた同期に「またか」と言われてました。 (だっていつしていいかわからない・・・) 実際、「commitのタイミング・頻度」ってどれくらいがいいのか、難しいところだと思います。 $ git add [ファイル名] $ git commit コマンドとしてはこれだけです。addしたファイルだけコミットされます。簡単ですね! ではcommitっていつすればいいのという話ですが・・・ 実は 絶対この時commitするべき 、 この時はしない方がいい というタイミングはありません。 (じゃあなんでこの記事書いたんだというツッコミはご遠慮ください) 実はこの問題、 僕もすごく悩みました 。 ネットで記事を探すと色々書いてありますが、僕が導き出した答えは以下の通りです。 会社の規則に従う(会社で決まっているタイミングで行う) 個人的に「この部分へは戻る可能性がある」と思ったとき タスク単位(機能単位)※単一機能追加のみ クラス単位(編集しているクラス1つにつき1回) 個人的な意見としては会社でグループ開発をしている場合は1つ目が絶対だと思います。 個人開発や他人に迷惑をかけない(自分のみが編集する部分)に関しては、個人のタイミングで良いと思います。 自分がcommitしてなくて最初からやり直し・・・なんてことになっても自分の責任で済みますからね・・・ 僕は研修の時はクラス単位でcommitしていましたが、配属されてからは機能単位でcommitしています。 commitする際の注意点 commitする時に注意したいのが、 余計なものはcommitするファイルに入れない ことです。 僕が配属されてから失敗したこととして、 commitしなくていい(しない方がいい)ファイルまでaddしてcommit していました。 つまり、 機能に関わりのない個人設定のファイル や 間違って編集したファイル はcommit対象にするべきではないということです。 理由としては、 余計なファイルが入ると、確認する際(個人環境に持ってきたとき)に動作の妨げとなることがある 機能単位で確認する際に編集した内容が見づらくなってしまう などがあげられます。(実際に先輩に指摘を受けました) 1点目についてはレビュワーへの被害が大きいです。余計なファイルがあると、どこを編集したのか確認が大変です。 2点目は1点目に繋がりますが、後から見た人が「これ編集してあるみたいだけど、どう関係してるファイル?」となってしまいます。 個人で開発しているならまだしも、グループ開発だと、周りに 多大な迷惑&手間 をかけてしまうことがあります。 おわりに 皆さん、いかがでしたか? commitのタイミングと注意点について個人的な意見ですがまとめてみました。 commitのタイミングについて困った方の参考になれば幸いです。 参考資料 はじめてのGit!コミット(commit)でファイルを登録してみよう 【初心者向け】「コミットの粒度がわからない問題」の模範解答を考えてみた エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
はじめに こんにちは。新卒2年目のtaku_76です。 以前FirebaseでLINEbotを作成するという勉強会に参加してきました。 しかし、元々Firebaseについて名前を聞いたことがあるくらいで知識が全くありませんでした。 そこで今回は実際に使ってみることで理解を深めようと思い、簡単なものではありますが FirebaseのRealtime Databaseを使ってリアルタイムチャットを作成しましたので、Firebaseとは、というところから紹介していきます。 はじめに Firebaseとは Realtime Databaseとは 実装 Firebaseでプロジェクトの作成 ログイン方法の設定 Realtime Databaseの作成 Firebaseの読み取りの書き込み データベース参照を作成 チャット作成 送信準備 送信処理 受信処理 終わりに 参考 Firebaseとは Firebaseは Google が提供しているモバイルおよび Web アプリケーションのバックエンドサービスです。 ユーザーの初期登録や認証を簡単に実装できる機能や、 ホスティング 機能など様々な機能がありますが、 今回はリアルタイムでクライアント全体の状態を同期させることができるRealtime Databaseを利用します。 Realtime Databaseとは クラウド ホスト型 NoSQLデータベースで、ユーザー同士でデータをリアルタイムで保存・同期ができる機能です。 編集したデータは クラウド に保存され、数ミリ秒で各端末に同期されるため、ユーザー同士はリアルタイムでの共同作業が可能になります。データは JSON フォーマットで保存されます。 実装 Firebaseでプロジェクトの作成 以下にアクセスしてプロジェクトを作成します。 https://firebase.google.com プロジェクトが作成できたらウェブアプリにFirebaseを追加します。 scriptタグが表示されるので、これを今回作成するファイルchatapp.htmlのscript内に貼り付けます。 ログイン方法の設定 ログイン方法を選択するのですが、今回は匿名を有効にしておきます。 Realtime Databaseの作成 次にRealtime Databaseの作成を行います。 左のメニューからDatabaseを選択し、Realtime Databaseを作成します。 ルールについては開発時なのでテストモードを選択します。 chatapp.htmlに入力欄のdivタグを追加します。 <div> <div> <input type="text" id="name"> </div> <div> <textarea id="message" row="10"></textarea> <button id="send">send</button> </div> <div id="output"></div> </div> Firebaseの読み取りの書き込み データベース参照を作成 データベースでデータの読み書きを行うためには、firebase.database.Referenceの インスタンス が必要ですので 以下のコードを追加します。 var database = firebase.database(); チャット作成 送信準備 var database = firebase.database(); let room = "chat_room"; const send = document.getElementById("send"); const name = document.getElementById("name"); const message = document.getElementById("message"); const output = document.getElementById("output"); let room ="chat_room";で指定したroomにデータを記録しています。 この値を変更することによってデータの格納先を変えることができます。 送信処理 send.addEventListener('click', function() { database.ref(room).push({ name:name.value, message:message.value }); message.value=""; name.value=""; }); メッセージの送信はpush()を使うことによってデータベースに登録することができます。 データベースへのデータを書き込むメソッドは他にもset(),update(),transaction()があります。 受信処理 database.ref(room).on("child_added", function(data) { const v = data.val(); const k = data.key; let str = ""; str += '<div class="name">名前:'+v.name+'</div>'; str += '<div class="text">メッセージ:'+v.message+'</div>'; output.innerHTML += str; }); Firebase内のデータを取得するためにchild_addedイベントを使用します。 このイベントは子ごとに1回トリガーされ、新しい子が追加されるとそのたびに再度トリガーされます。 今回の実装では、push() メソッドによる新しい子の追加で、child イベントがトリガーされるという動作になっています。 実装完了後、2つのブラウザを立ち上げて動作確認を行います。 nameとmessageを入力してsendボタンを押すことで、以下のようにリアルタイムにチャットができたら成功です。 FirebaseのRealtime Databaseを見てみるとnameとmessageが記録されていることも確認できます。 以上でリアルタイムチャットの実装は完了になります。 終わりに Firebaseを使うことによってデータベースへの読み書きが楽になり、 リアルタイムチャットの開発がすごく簡単になったことを実感しました。 Firebaseを理解して使いこなせるようになると個人的に開発する際のコストを下げられると思いましたので、他の機能も学習していきたいと思います。 参考 www.topgate.co.jp アプリ開発が怖いほど楽になる「Firebase」を徹底解説!【初心者向け】 ウェブでのデータの読み取りと書き込み  |  Firebase Documentation ウェブでのデータの読み取りと書き込み  |  Firebase Documentation エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
はじめに こんにちは、strongWhiteです。今回は大阪オフィスで開催された9月ビアバッシュをご紹介いたします。 前回の記事はこちら↓ tech-blog.rakus.co.jp はじめに 発表一覧 個人的に気になった発表 1日で学ぶ機械学習 エンジニアの知的生産術を読んで スクリプト言語のベンチマーク おわりに 発表一覧 今回はオンラインでつないで東京オフィスのエンジニアと合同で開催することとなりました。 以下が今回の発表一覧です。多くの方に発表していただきました! 自由枠(質疑応答込みで13分) らくらくでないLINE@連携 まず、やってみる(社内/社外イベント取り組みの振り返り) 1日で学ぶ 機械学習 社外イベント登壇の取り組みの実績 エンジニアの知的生産術を読んで GASとclaspについて iOS13で実装された念願の『アレ』の話 LT枠(5分厳守) Akka(と scala )でたこ焼きを焼く スクリプト言語 の ベンチマーク reveal.jsについて 全体に触れると長くなってしまうため、個人的に気になった発表をピックアップしてご紹介いたします。 個人的に気になった発表 1日で学ぶ 機械学習 Chainerが公開している 機械学習 の学習教材に取り組んだお話でした。 機械学習 と聞くと漠然と難しいイメージですが、この教材では Python や数学、確率・統計の基礎から学べるので入門者にはとっておきの学習教材です。 開発環境は Google Colaboratoryを使えば、初めから主要なライブラリを利用することができます。 個人的には開発環境構築が必要ないのは、学習の負担削減になり魅力的だなと感じました。 機械学習 は マーケティング や製造、情報セキュリティなど様々な分野で活用されており、いまホットなテーマなので、基礎を学ぶにはちょうどいいなと思いました。 Information Chainer Google Colaboratory エンジニアの知的生産術を読んで 『エンジニアの知的生産術』を読んで実践したことを共有していただきました。 書籍には「学びのサイクル」が紹介されており、すなわち情報収集→モデル化→検証→※最初に戻るを繰り返すことで学びを繰り返すことができます。自分が学びたいことを「情報収集」し、集めた情報を KJ法 などで「モデル化」、最後にモデル化した情報を本当に理解しているか「検証」するフェーズを実施します。 個人的にはそもそも何を学べばいいかわからない事態に陥ることが多いのですが、ひとまずは(IT分野に限らず)興味のあるものは何でも学んでみようというスタンスで「学びのサイクル」を実行するとうまく知識が定着するのかなと思いました。 Information エンジニアの知的生産術 KJ法 スクリプト言語 の ベンチマーク 各言語の最新バージョンで ベンチマーク を実施したお話でした。 対象言語はWeb界隈でメジャーな PHP 、 Ruby 、 Python 、 Perl 、Node.jsで、 フィボナッチ数列 や竹内関数(たらい回し関数)などを検証されました。 今回の発表では主にNode.jsが速く、検証する関数に 再帰 が多いと速いのかもしれないという推測ができました。 個人的には一時期流行った「ズンドコキヨシ」の ベンチマーク を実施した話が面白かったです。5000回実行した場合の時間を計測されましたが、結果的には Perl が一番速かったです。 Information フィボナッチ数列 竹内関数 ズンドコキヨシ おわりに 今回は東阪合同だったのがとても新鮮でした。ふだん関わりの少ないメンバーも積極的に発表に参加してくださり、いつものビアバッシュとは違った雰囲気でした。 今年度入社・配属された方も発表に参加してくださり、ますますビアバッシュが盛り上がっていく感じがします。 今後もビアバッシュの内容はブログという形でレポートしていきますので、どうぞお楽しみに!!
アバター
はじめに こんにちは、新卒3年目エンジニアの @rs_tukki です。先日開発オフィスが移転となり、美味しい昼食を探し求める日々が続いています。 さて、来る9/20(現地時間)、ついにiOS13がリリースされました! ダークモードやSwiftUIなど、利用者としてだけでなく開発者としても魅力的な機能が様々追加されているそうですが、今回はその中でも、ついにアップデートされたCoreNFCについてまとめてみます。 はじめに CoreNFCとは 今までは Suicaの履歴を読み取ってみる Xcodeプロジェクトの設定 読み取り開始まで 読み取った内容の解析 結果確認 まとめ 参考 CoreNFCとは CoreNFCとは NFC 規格の通信 フレームワーク のことで、 apple ではiOS11から採用されていました。 NFC は近距離無線通信の略で、よく皆さんが使っている Suica や Edy などの 電子マネー や、最近では マイナン バーカードなどにも搭載されている「かざして通信する」ことができるシステムを総称してこう呼びます。 iOS13からは、このCoreNFCの機能がアップデートされ、上記のようなカードの読み書きが、 サードパーティ 製のアプリでも行えるようになりました。 今までは iOS12までのCoreNFCは、NDFC( NFC Data Exchange Format)という規格の「読み取り」にしか対応していませんでした。 NDFCはURLなど超小容量のデータしか通信できないため、CoreNFCと言いながらもほぼ QRコード と同等以下のシステムでしかないと言えます。 iOS12までで Suica カードなどの読み取りを行いたい場合、 iPhone と外部機器を BlueTooth で接続する必要がありました(当然、書き込みはできません)。 楽楽精算のICリーダーも、 iOS 版はこの仕組みで読み取っています。 楽楽精算ICリーダー 株式会社 ラク ス ビジネス 無料 apps.apple.com Suica の履歴を読み取ってみる というわけで早速、アップデートされたCoreNFCの機能を使い Suica の乗降履歴情報を取り込んでみましょう。 実装については以下のサイトを参考にさせていただきました。 iOSでSuicaの履歴を読み取る - Qiita Xcode プロジェクトの設定 まずは、 Xcode のプロジェクト上でCoreNFCを使用するための設定を行います。 プロジェクトを開き、TARGETS>Signing & Capabilitiesから左上の「+」ボタンを押すと、プロジェクトに追加するネイティブ機能を選択できます。 iOS13に対応した Xcode であれば、 Near Field Communication Tag Reading (= NFC タグの読み取り)の機能があるので、この機能を有効にします。 続いて、Info.plistを編集します。 ISO18092 system codes for NFC Tag Reader Session には、読み取りたいカードの「システムコード *1 」を入力します。 たとえば、 Suica や PASMO などの 交通系ICカード を読み取りたい場合、システムコードは0003になります。 配列型で複数のシステムコードを登録できますが、 ワイルドカード で全てのカードを読み取れるようにする...といったことは残念ながらできません。 読み取り開始まで さて、前準備も終わったところで早速カードの読み取りをしてみましょう。 まず初めに、CoreNFCをインポートしておきます。 import CoreNFC カードを読み取らせるときは、 NFCTagReaderSession 型の変数を定義しておき、どのような規格のカードを読み取るか設定します。iso18092は NFC TypeF、つまり Suica に代表される Felica 規格のことを指します。 bigin() を呼び出すとカードの読み取り状態になります。現在のところは iOS 固有のUIが表示されるため、独自の読み取り画面を表示させるといったことはできなくなっています。 //NFCタグを読み取るための変数を定義 var session : NFCTagReaderSession? :   (中略) : //読み取り開始時 self .session = NFCTagReaderSession(pollingOption : .iso18092, delegate : self ) self .session?.alertMessage = "カードをiPhoneに近付けてください。" self .session?.begin() カードを読み取る際は、それぞれ以下に記載したタイミングで3つのメソッドが呼ばれます。 もし読み取りが何らかの理由で失敗した場合は、2番目のメソッド内で error 引数を元にエラーハンドリングを行います。 //読み取り状態になったとき func tagReaderSessionDidBecomeActive (_ session : NFCTagReaderSession ) { } //読み取りが完了したとき func tagReaderSession (_ session : NFCTagReaderSession , didInvalidateWithError error : Error ) { } //読み取りが成功したとき func tagReaderSession (_ session : NFCTagReaderSession , didDetect tags : [ NFCTag ] ) { 読み取った内容の解析 続いて、読み取りに成功してからの処理です。 引数の tags には、読み取った全ての NFC 対応カードの情報が入っています。最初に認識したカードが正しく読み取れているか、 Felica 規格のものかどうか確認しておきましょう。 func tagReaderSession (_ session : NFCTagReaderSession , didDetect tags : [ NFCTag ] ) { let tag = tags.first ! session.connect(to : tag ) { (error) in if nil != error { print( "Error: " , error) return } guard case .feliCa( let feliCaTag ) = tag else { session.alertMessage = "FeliCa以外の規格が検出されました。FeliCa規格のカードで再試行してください。" return } このタイミングで、既に IDm *2 と、先ほど指定したシステムコードは読み取ることが出来ます。 更に乗車履歴などの詳細な情報を読み取る場合、その情報が格納されている場所を サー ビスコ ード として指定します。このとき難儀なのが、サー ビスコ ードをリ トルエン ディアン *3 で指定しなければいけない、ということです。有志の方のサンプルコードを読む前に私も実装にチャレンジしてみたのですが、ここの指定が上手くいかず挫折していました... その後は読み取る範囲を指定してから、 requestService でいよいよ乗車履歴を読み出します。 中身のデータが存在していればFFが返ってくるはずですので、そこも一度確認しておきましょう。 let idm = feliCaTag.currentIDm.map { String(format : "%.2hhx" , $0 ) }.joined() let systemCode = feliCaTag.currentSystemCode.map { String(format : "%.2hhx" , $0 ) }.joined() let serviceCode = Data([ 0x09 , 0x0f ].reversed()) feliCaTag.requestService(nodeCodeList : [ serviceCode ] ) { nodes, error in if let error = error { print( "Error:" , error) return } guard let data = nodes.first, data != Data([ 0xff , 0xff ]) else { print( "履歴情報が存在しません。" ) return } Suica をはじめとする 交通系ICカード は全部で20件の乗降履歴を保持できますが、現在の使用では一度に12件までしか読み取れないようです。 読み取る範囲を指定したら readWithoutEncryption を実行します。戻り値としてstatusが2種類返ってきますが、この値が両方とも00であれば、めでたく履歴を取得できています。 読み取り中のUIは session.invalidate() で閉じておきましょう。 中身のデータがどのような形式で格納されているか...についてですが、独自に解析している方がおり、それを参考にすることができます。 今回はサンプルコードから引用させていただきましたが、参考資料にはデータの格納情報が更に詳しく載っていますので、気になる方は読んでみてください。 let block :[ Data ] = ( 0 ..< 12 ).map { Data([ 0x80 , UInt8( $0 )]) } feliCaTag.readWithoutEncryption(serviceCodeList : [ serviceCode ] , blockList : block ) {status1, status2, dataList, error in if let error = error { print( "Error: " , error) return } guard status1 == 0x00 , status2 == 0x00 else { print( "ステータスコードが正常ではありません: " , status1, " / " , status2) return } session.invalidate() print( "IDm: \( idm ) " ) print( "System Code: \( systemCode ) " ) dataList.forEach { data in print( "年: " , Int(data[ 4 ] >> 1 ) + 2000 ) print( "月: " , ((data[ 4 ] & 1 ) == 1 ? 8 : 0 ) + Int(data[ 5 ] >> 5 )) print( "日: " , Int(data[ 5 ] & 0x1f )) print( "入場駅コード: " , data[ 6 ... 7 ].map { String(format : "%02x" , $0 ) }.joined()) print( "出場駅コード: " , data[ 8 ... 9 ].map { String(format : "%02x" , $0 ) }.joined()) print( "入場地域コード: " , String(Int(data[ 15 ] >> 6 ), radix : 16 )) print( "出場地域コード: " , String(Int((data[ 15 ] & 0x30 ) >> 4 ), radix : 16 )) print( "残高: " , Int(data[ 10 ]) + Int(data[ 11 ]) << 8 ) } } } } } 結果確認 さて、ここまでの実装を踏まえて実際に Suica を読み取ってみると... IDm システムコード 利用年月日 入場駅コード・出場駅コード 入場地域コード・出場地域コード *4 残高 が取得できているのが分かるかと思います! まとめ 今回は、iOS13でアップデートされたCoreNFCについて説明しました。 Android ではかなり前から読み取れていましたが、ようやく iOS も追いついた形になります。これを機に今までのアプリも色々アップデートされていきそうで楽しみです! 参考 iOS13 CoreNFCの使いみちとQRコード、BLEとの比較 - Qiita iOS13ではNFC機能をサードパーティに開放、行政手続きなどに利用可能 - iPhone Mania 「iOS 13」ベータ版をインストールする方法 iOS 13 で FeliCa (Suica) にアクセス | notes from E iOSでSuicaの履歴を読み取る - Qiita エラー ‐ 通信用語の基礎知識 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com *1 : カードの利用目的ごとに割り振られた番号 *2 : カードごとに割り振られた番号 *3 : http://e-words.jp/w/%E3%83%AA%E3%83%88%E3%83%AB%E3%82%A8%E3%83%B3%E3%83%87%E3%82%A3%E3%82%A2%E3%83%B3.html *4 : 0はJR、もしくは関東の私鉄、バスを指す。
アバター
こんにちは、新卒2年目のEngawaです。 今回はサーバにデプロイしたWEBアプリを Eclipse でリモート デバッグ する方法を書いていきたいと思います。 はじめに 普段から開発を行っている際は、 Eclipse の デバッグ 機能を使い処理の流れや変数の値を確認しながら実装しているのですが、ローカル環境では実行できない部分(外部サービスと連携した後の処理とか)の実装では処理の流れや、変数には何が入っているかわからない上、動作確認もサーバにデプロイして確認しているのですが、エラーが出た時も詳細なエラー原因を探すのに苦労しました。 そこでサーバにデプロイしたWEBアプリを Eclipse でリモート デバッグ する方法を簡単にまとめてみました。 はじめに 設定 終わりに 参考 設定 まずは Tomcat の設定からです。 起動シェルの以下の1文を変更 $SU - $ TOMCAT _USER -c "${CATALINA_HOME}/bin/catalina.sh start" ↓ $SU - $ TOMCAT _USER -c "${CATALINA_HOME}/bin/catalina.sh jpda start" 上記内容で変更したら Tomcat を再起動して、 Tomcat の設定の変更は完了。 続いて、 Eclipse の設定を行います。 1. 実行 > デバッグ の構成 > リモート Java アプリケーションを右クリック > 新規構成 を選択 2. プロジェクト に デバッグ するプロジェクトの名前、 ホスト に接続先の IPアドレス をそれぞれ入力(それ以外はデフォルトで問題なし) 3. 適用を押下 これで設定は完了です。 設定完了後、 デバッグ で実行し、 デバッグ タグで接続先の IPアドレス が表示されれば接続完了です。 あとはいつも通り ブレークポイント を置いてからブラウザでアクセスすると、 ブレークポイント を置いた部分で処理が止まってくれます。 終わりに 今回はサーバにデプロイしたWEBアプリを Eclipse でリモート デバッグ する方法について簡単にまとめました。 同じような境遇になった方の参考になれば幸いです。 参考 qiita.com www.ibm.com エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター
初めまして、hidePoohです。 第四回を担当させていただきます。 私たちが住む日本では、携帯電話という文化は独自の進化をしてきました。 キャリアメールも例外ではなく、各キャリアごとに特徴を出したものへと進化してきました。 なお、「キャリアメール」とは携帯電話事業者が各社ごとに提供している( ~@ docomo .ne.jp、~@ ezweb .ne.jp、~@ softbank .ne.jp などの)メールのことです。 詳細は下記をご参照ください。 ja.wikipedia.org これまでのキャリアメールは携帯電話と一緒に進化してきた キャリアごとに違う 文字コード 日本のPC向けメールの 文字コード は一般的に「 ISO-2022-JP 」が使われています。 ですが、携帯向けの 文字コード は、各キャリアごとに 文字コード に違いがあります。 ※キャリアとは    NTTドコモ 、 au 、 ソフトバンクモバイル などの携帯電話会社の事を指します。 NTTドコモ :Shift-JIS au :Shift-JIS ソフトバンクモバイル : UTF-8 上記のように、配信されるアドレス(キャリア)によって 文字コード を変える必要がありました。 特に、昨今のシステムは UTF-8 が主流となっています。 キャリアごとの 文字コード を対応させることはとても面倒ですね。 絵文字の登場 日本の携帯といえば、「絵文字」が有名ですね。 現在では、 “emoji”という言葉があるくらい、世界中に広がりました。 でも当初登場したときは、キャリアごとにバラバラで配配メール側での実装も大変だったと聞いています。 ※ NTTドコモ が提供しているドコモ絵文字の一部 *1 絵文字は、キャリアごとに種類も違い、絵文字の種類も数も違います。 配配メールでも例外ではなく、どのように考慮するか大変でした。 現在では、キャリア同士でも、絵文字の違いを保管できるように各絵文字専用の 文字コード を用意し、配信時にその 文字コード を指定する仕様が公開されています。 ※ NTTドコモ が提供している絵文字変換表 https://www.nttdocomo.co.jp/binary/pdf/service/imode_mail/function/emoji_convert/pictogram.pdf ※配配メールでは、上記の図のドコモ絵文字から各キャリアのコードをマッチングできるような仕組みを構築しています。 配配メールではこれらの進化に合わせてキャリアメールに対応している ここまで説明したように、配配メールの送信PGでは 文字コード ・絵文字を配信されるアドレス(キャリア)ごとに処理を行うようにしています。 メール作成:本文内の絵文字挿入(ドコモ絵文字) ------ メール配信処理開始 ------ メール配信処理開始 配信するアドレスからキャリアを確認 本文内に絵文字が見つかったら、配信アドレスに合わせて各キャリアごとの絵 文字コード 表から対応する絵文字に変換    → PG内部で絵 文字コード 用 マトリックス を作成しており、送信時に変換処理を実施 文字コード を変換 配信完了 こうやって書くと簡単に見えますが、携帯向け配信は各キャリアごとの仕様を把握しながら配信しなければならず、とても面倒な作業です。 スマホ の登場によってこれらの違いがなくなりつつある ここまで書いてきたのは、特に“ フィーチャーフォン (※ ガラケー )”を意識した配信です。 最初に書いたように日本は、キャリアが携帯機種を開発している歴史があり、機種に依存した問題も多く、キャリアが提供している仕様に合わせる事が大事でした。 ですが、“ スマートフォン (※ スマホ )”の登場で大きく変わりつつあります。 スマホ が登場したときは、各キャリアの仕様がそのまま適用されており、 ガラケー と同じように扱うような仕様となっていました。 最近は、 Gmail や Yahoo! メールなどの フリーアドレス も多く利用されるようになり、ほぼPCと同じ仕様でメールを配信する事ができるようになりました。 文字コード の制限もなくなりつつあります。 (※キャリアメールは 文字コード に準拠する必要がありますが、そこは置いといて・・・) また、絵文字も大きく変わりつつあります。 Unicode での絵文字が提供されたことです。 つまり、 Unicode ( UTF-8 )であれば、絵文字を表示させることができるようになりました。 ja.wikipedia.org ※ Unicode の絵文字の一部 この絵文字を使えば、 スマホ でも、PC向けメールにも同じ絵文字を配信できるようになります。 また、 文字コード も UTF-8 に統一され、受信する媒体(PC・ スマホ )に関係なく、同じ仕様で配信する事が可能になります。 今後、携帯はPCとの垣根なく対応させることができるようになる!(と、私は思っている) まとめ 日本独自の進化をとげた携帯電話というデ バイス 。 でも、 スマホ の登場で色々な事がかわりつつあります。 我々、メール配信システムを作るものとしても、統一した仕様での実装ができることはとてもうれしい事でもあります。 特に私が入社したころは、以下のような事がよくありました。 ○○の機種だけで文字化けするんですけど・・・ 絵文字が正しく表示されないんですけど・・・ 今後は、携帯電話というものから、PCも携帯電話も一緒のメールが統一して送信する事ができる! そんな配信がすぐそこまで来ていると思います。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 forms.gle イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! rakus.connpass.com *1 : NTTドコモ : https://www.nttdocomo.co.jp/service/imode_mail/function/pictograph/
アバター
みなさんこんにちは。フジサワです。 前回の記事 でお伝えしていたElasticsearchの検証がひと段落しましたので、検証結果をレポートいたします。 連載目次 『全文検索 〜 Elasticsearchとデータ匿名化手法』 『全文検索の探求 Elasticsearch(1) 』: プロジェクト方針およびElasticsearch概要 大量データを検索するサービスでElasticsearchはRDBの代替候補になりうるか?(Elasticsearch vs pg_bigm)』 ←今読んでいる記事 データ匿名化 第1回:匿名化された個人情報とは何なのか データ匿名化 第2回:個人情報は匿名化しても意味がないのではないか? データ匿名化 第3回:個人情報を匿名化するプロセス データ匿名化 第4回:匿名化のために行うデータ項目の一般化とは データ匿名化 第5回:データ匿名化の指標 データ匿名化 第6回:実際の匿名化 はじめに 検証を行うにあたり、私たちは前回、以下の通りゴール設定をしました。 『検索機能を有する新規サービスの アーキテクチャ 検討段階で、 RDB だけでなくElasticseachが比較検討材料として挙がる状態を作る』 この検証を行うにあたり、以下のようなサービスをモデルとして設定しました。 扱うデータのレコード数は、多くても100万件オーダー ※当社はBtoB向けのサービス、かつ中小企業のお客様を主たる顧客層としているので、1顧客でウン千万件、ウン億件というようなレコードが発生するケースよりは上記程度のデータ量が検証対象としては妥当だろうと判断しました。 テキストデータに対する、中間一致検索(いわゆるLIKE検索)機能を持つ ※従来の技術領域を代替するもの、という位置付けで RDB でパフォーマンス劣化が発生しがちな中間一致検索を採用 また、当社では RDB に PostgreSQL を採用する場合が多いのですが、デフォルトの PostgreSQL では比較の余地がないので、 PostgreSQL の 全文検索 プラグイン である pg_bigm を比較対象として採用することにしました。 結論から言うと… 「従来型のLIKE検索を行う代替手段」としては、速度・機能面でElasticsearchは候補になりうる。しかし、その目的だけであれば、pg_bigmを採用するほうがデメリットが少なく、わざわざElasticsearchを導入する必要は無い。 Elasticsearchを採用するのであれば、 形態素 型インデックスの特徴を活かした「自然な文書検索」や「あいまい検索」、「スケーラビリティ」などの要件を重視するべきである。 いずれを選択するかは、機能要件・用途や、データの特性に応じて選択をすべきである。 以下、上記結論に至った検証結果をご覧ください。 データストアとしての振る舞いの特徴 検証結果をお伝えする前に、Elasticsearchのデータストアとしての特徴を確認しておきましょう。 ドキュメント型データベースである ElasticSearchはドキュメント型データベースで、自由なレイアウトでのデータ表現が可能です。 スキーマ にとらわれず、様々な形式の文書データを横断的に検索することに優れています。 スケーラブル Elasticsearchはデー タセット を分割の最小単位となるシャードに分け、複数のノードにシャードを分散して配置します。シャードを動的に再配置することで柔軟にスケールアウトさせることができます。 トランザクション がない Elasticsearchには トランザクション がありません。データの登録に失敗した、登録中に他プロセスから検索がかかった、といったACID性を求められる局面では別途考慮が必要です。 結合は不得手 前述の通り、Elasticsearchは複数のノード(およびシャード)にデー タセット を分散して保持します。この特性から、 RDB における正規化、結合といった使い方には適していません。 また、インデックス間の結合を行う機能はなく(限定的に、親子関係での結合を行うことはできる)、出来るだけ非正規化することが 推奨されています 。 こうした特徴から単純に RDB の代替として採用するというよりは、 大量の文書を高速に検索することに適した仕組み を活かして、限定的に使用するのが良いでしょう。 検証: PostgreSQL のLIKE検索と同じ検索結果を得ることができるか Elasticsearchを使用した場合でも、 PostgreSQL のLIKE検索と同様の結果を得ることができるのでしょうか。 結論から言えば、 PostgreSQL のLIKE検索と同様の検索結果を得ることができる ことが分かりました。 ただし、 Analizerについての前提知識とその特性について理解 したうえで、 match_phraseクエリを使用する 必要があります。 Analizerとは Elasticsearchにおける、文書データ、および検索クエリ文字列を分解・加工することで効率よく検索を行うための仕組み。 文書データをインデキシングする際、「一定のルール」に従って文字列を分割する。 検索クエリに対しても同じルールで文字列を分割し、分割された状態で検索を行うため、1バイトずつ探索を行うのに比べて、高速に検索を行うことができる。 この、「一定のルール」を司るのがTokenizerと呼ばれるもので、 形態素解析 型、 N-Gram 型(文字列をN文字長分割する)などがある。 文書データをどう扱いたいのかによって、どのようなAnalizerを選択するかを決定する必要がある。 形態素解析 型を用いたAnalizer(Kuromoji Analysis Plugin)の場合 形態素解析 型を用いた場合、「 全文検索エンジン 」という文字列は次のように分割されます。 curl -X POST -k -H 'Content-Type: application/json' '/_analyze' --data '{ "analyzer" : "kuromoji", "text" : "全文検索エンジン" }' { "tokens": [{ "token": "全文", "start_offset": 0, "end_offset": 2, "type": "word", "position": 0 }, { "token": "検索", "start_offset": 2, "end_offset": 4, "type": "word", "position": 1 }, { "token": "エンジン", "start_offset": 4, "end_offset": 8, "type": "word", "position": 2 }] } N-gram 型のAnalizerの場合 N-gram 型を用いた場合、「 全文検索エンジン 」という文字列は次のように分割されます。 なお、検証に使用したAmazonESには、 N-gram 型のAnalyzerがありませんので、自分でTokenizerを指定してカスタムAnalyzerを定義しています。 curl -X PUT -k -H 'Content-Type: application/json' '/bigram' --data '{ "index":{ "analysis":{ "tokenizer" : { "bigram" : { "type": "nGram", "min_gram" : 2, "max_gram" : 2, "token_chars": [ "letter", "digit" ] } }, "analyzer" : { "bigram" : { "type" : "custom", "tokenizer" : "bigram" } } } } }' curl -X POST -k -H 'Content-Type: application/json' '/bigram/_analyze' --data '{ "analyzer" : "bigram", "text" : "全文検索エンジン" }' { "tokens": [{ "token": "全文", "start_offset": 0, "end_offset": 2, "type": "word", "position": 0 }, { "token": "文検", "start_offset": 1, "end_offset": 3, "type": "word", "position": 1 }, { "token": "検索", "start_offset": 2, "end_offset": 4, "type": "word", "position": 2 }, { "token": "索エ", "start_offset": 3, "end_offset": 5, "type": "word", "position": 3 }, { "token": "エン", "start_offset": 4, "end_offset": 6, "type": "word", "position": 4 }, { "token": "ンジ", "start_offset": 5, "end_offset": 7, "type": "word", "position": 5 }, { "token": "ジン", "start_offset": 6, "end_offset": 8, "type": "word", "position": 6 }] } 上記において、例えば「エンジ」というキーワードで検索を行った場合、 形態素 型のAnalizerを用いた場合はHitせず、N-gran型のAnalyzerを用いた場合はHitします。 もし、Elasticsearchを、 RDB の代替としてLIKE検索と同等の検索を行うのであれば、 N-gram 型のAnalyzerを使用することで実現できます。 一方で、 形態素 型のAnalyzerを使用する方が、検索結果としてはより自然な検索結果を得ることができます。 今回は、LIKE検索の代替という観点で検証するため N-gram 型を採用しましたが、Analyzerの選択については、本来は下記の基準で選ぶことになります。 確実にキーワードが含まれる検索結果を得たい場合 ⇒ N-gram 型 取り漏らしがあるが、自然な結果を得たい場合 ⇒  形態素 型 なお、Elasticsearchは、複数のAnalyzerを複合的に用いることもできますが、これについては今回の検証内容からは外しています。 match_phraseクエリ Elasticsearchを用いて 全文検索 を実行する際、どのような問い合わせを実行するかを指定することができます。 クエリ一覧 match クエリは、指定したクエリ文字列をAnalizerによって分解し、 それぞれのトークンの順序によらず、トークンが含まれているかどうか によって検索結果を導出します。 GET /_search { "query": { "match" : { "message" : { "query" : "全文検索エンジン" } } } } 例えば、「 全文検索エンジン 」というキーワードで問い合わせを行った時、AnalyzerにKuromojiを使用していれば、検索キーワードは 全文 、 検索 、 エンジン という3つの トーク ンに分割されます。 この時、「 全文検索エンジン とは」という文章だけでなく、「 エンジン が 全文 を 検索 します」という文章も、検索結果にHitします。 一方、LIKE検索のような中間一致検索にElasticsearchを使用したい場合は、 match_phrase クエリを使用する必要があります。 GET /_search { "query": { "match_phrase" : { "message" : { "query" : "全文検索エンジン" } } } } match_phraseクエリは、 それぞれのトークンの順序・出現位置が一致する ものを検索結果に導出します。 ですから、「 全文検索エンジン とは」という文章はHitしますが、「エンジンが全文を検索します」や、「全文を検索するエンジンです」といった文章はHitしません。 検証: PostgreSQL (pg_bigm)と比較してどれだけの検索性能が発揮できるか 次に、Elasticsearchとpg_bigmの検索速度の比較による検索性能の検証結果を見ていきましょう。 pg_bigmとは? PostgreSQL 上で動作する日本語に対応した 全文検索 用モジュール N-gram 方式で、2文字単位で分割する インストールやインデックスの構築が容易 SQL をそのまま利用できる 公式ドキュメント 検証に使用したデータ、およびデータ量 Wikipediaの日本語版全データ データ件数:約230万件 計測方法 無作為に選定したキーワード群からランダムに選定したキーワードを用いて1000回問い合わせを行い、問い合わせに要した時間(ネットワーク経路に係る時間などを除く)と、対象のキーワードでHitした文章の数をグラフにプロットする Elasticsearch、pg_bigmを適用した PostgreSQL 、無調整(B-treeインデックス)の PostgreSQL の3者に対して同様の検索を行い、グラフを比較する 計測に使用した環境 それぞれの検証に使用した環境およびスペックについては下記の通りです。なお、Elasticsearchは最小構成でも3ノードを要するうえ、Elasticsearchも PostgreSQL も、チューニングによって性能が変わるため、厳密にスペックを揃えることはしていません。(※傾向を掴むことを主目的としています) Elasticsearch Amazon Elasticsearch Service v6.7 インスタンス タイプ:t2.small × 3ノード PostgreSQL (pg_bigm) Amazon EC2 上に PostgreSQL をインストール(RDSではpg_bigmがサポートされていないため) v9.6( PostgreSQL ) v1.2(pg_bigm) インスタンス タイプ:t2.large × 1ノード PostgreSQL (デフォルト) Amazon EC2 上に PostgreSQL をインストール v9.6( PostgreSQL ) インスタンス タイプ:t2.large × 1ノード 計測結果と考察 まずはデフォルト(B-treeインデックス)の PostgreSQL の計測結果を見てみます。キーワードやそのキーワードのHit件数によらず、最低でも50秒以上の時間を要することがわかります。これは、キーワードによらず、シーケンシャルスキャン(テーブルの全レコードの走査)が行われるため、一定の時間がかかっていることが要因です。 デフォルトの PostgreSQL 次に、同一のスケールの場合のElasticsearchとpg_bigmの計測結果を見てみましょう。 この結果を見ると、双方、キーワードにHitするレコードの数に応じて速度が遅くなっている事が分かります。デフォルトの PostgreSQL が固定でシーケンシャルスキャンのコストがかかっているのに比べると、高速化が見込めることが分かります。しかし、キーワードHit数が多くなるにつれて、検索速度がかなり遅くなっていくようです。場合によっては、デフォルトの PostgreSQL と同等のパフォーマンスになるケースがあるようにも見えます。 Elasticsearch pg_bigm ※なお、このグラフを見ると、pg_bigmの方が高速であるように見えますが、これは検証に使用した環境の性能差によるものだと考えられます。ここでは詳細を述べませんが、Elasticsearchのノード数を増やす、 インスタンス タイプのグレードを上げることで、検索速度が向上することが確認できています。 先ほどのスケールでは分かりにくいので、もう少し拡大したグラフで計測結果を見てみましょう。 これを見ると、Hit件数が少ない場合(1000件~2000件程度)であれば、遅くとも数秒以下の速度で検索結果が得られているようです。 elasticsearch(拡大) pg_bigm(拡大) では、次のデータを見てみましょう。これはElasticsearch,pg_bigm双方で、「検索キーワードにHitした先頭10件」を検索するのに要した時間です。試行回数は1000回、単位はmsecです。   Elasticsearch pg_bigm 平均値 9 75 中央値 10 25 最大値 159 3641 これを見る限り、最大値こそpg_bigmで少し遅い結果が得られていますが、平均値・中央値を見る限り、「キーワードにHitする件数によらず、全体から先頭の少数の結果を取得することは、十分に高速な速度で実行できる」ということが分かります。 つまり、ここまで見てきた結果から、Elasticsearch, pg_bigmはいずれも次の傾向であると言えると考えられます。 キーワードにHitする件数によらず、全体から先頭の少数の結果を取得することは、十分に高速な速度で実行できる キーワードにHitする件数が膨大で、そのすべての結果を得る場合はデフォルトの PostgreSQL と同等、ないしそれ以上の時間を要する 一般的に、膨大な検索結果を一度に取得するケースは少なく、ページネート機能や無限スクロール機能を持ったUIデザインを用いて、部分的に順次読みだしていくという利用シーンの方が多いと考えられるため、後者のデメリットが顕在化することはあまりないのではないかと考えられます。 以上から、 検索速度という点 においては、 Elasticsearchとpg_bigmの間には決定的な差が無く、双方とも必要十分な検索性能を有する のではないか、という結論に達しました。 なお、今回は詳細に触れませんが、 RDB でLIMIT-OFFSETを使用して、集合の後半の検索結果を得る場合、速度が遅くなるケースがあります(これは SQL チューニングなどで対応できます)。 この現象はElasticsearchでも同様で、これを解決する手段として、Elasticsearchは次のような機能をデフォルトで持っています。 Search After ページネーションに最適化された検索方式で、検索結果を先頭ページから順次検索する際に利用できる Scroll 検索結果をキャッシュして、後から部分的に再利用できるようにする仕組み。初回のキャッシュ作成時は時間がかかる。 まとめ Elasticsearchは『速度改善』だけで選ぶものではない 私たちは、当初Elasticsearchを導入することによって検索機能の速度改善が見込めるのではないかという仮説に基づき検証を進めてきましたが、速度改善だけを主目的として導入の判断をすべきではないということが分かりました。 従来型の検索方式や使い方だけで判断するのであれば、わざわざElasticsearchを導入する必要はなく、pg_bigmでも十分に速度改善を見込む事ができます。 Elasticsearchには次のようなデメリットがあり、必ずしも選定条件として優位とは言えません。 Elasticsearchとpg_bigmを比較した場合のデメリット 学習コストがかかる Elasticsearchの特性や運用方法についての理解、 REST API の使い方を新たに習得する必要があります。一方、pg_bigmであれば、既存の SQL の知識をそのまま活用することができます。 別のサーバーリソースを要する Elasticsearchを耐障害性なども考慮して使用する場合、最低でも3台のノードを必要とし、 RDB とは別にリソースを確保する必要があります。 正規化できない、 トランザクション がない 前述の通り、Elasticsearchは正規化や結合が苦手ですので、マスタDBを使用した絞り込みなどの用途には向いていません。 また、 トランザクション が無いため、ACID性を期待しないか、または、別途仕組みを講じる必要があります。 この点においては、 PostgreSQL と一体になっているpg_bigmの方が設計やデータの取り回しがしやすいと言えるでしょう。 ※pg_bigmにも「インデックスサイズが大きくなる」「更新処理にオーバーヘッドが増える」というデメリットがありますが、これはElasticsearchを採用した場合と比較しての明確なデメリットとは言えないと考えています。 餅は餅屋である では、Elasticsearchはどのようなシーンで採用するべきなのかというと、 「Elasticsearchでしかできないこと」 が開発するシステムの要件に含まれている場合だと考えています。具体的には、 自然言語 で記述された大量の文書データに対して、 より文章として自然な検索結果を得たい 検索キーワードを基にした あいまいな検索結果を得たい システムの運用を継続するにつれて肥大化していくデータに対して、 動的に クラスタ 構成をスケーリングしたい というようなシーンではないでしょうか。こうした点については、 RDB では対応が難しい場合が多く、文章の検索に特化したElasticsearchならではの活用範囲であると考えています。 つまり、 従来型の検索方式の『代替』としての役割を期待することが間違っている のであり、 Elasticsearchの得意分野、かつ RDB では代替できないところ に採用することで、 Elasticsearchの価値が享受できる ということです。 最後に 今回の検証を行うまでは、ただ漠然と「Elasticsearchを使うと 全文検索 が速くなるらしい」といった程度の認識でしかありませんでしたが、検証を通して、Elasticsearchの特性や、活用範囲などを理解することができました。 今後、新規サービスの アーキテクチャ を検討する段階で、Elasticsearchの特性がうまく適用できるかどうか、という点が、 アーキテクチャ 選定の材料にできると考えています。 今回の検証結果が、少しでも皆様のお役に立てば幸いです。 連載目次 『全文検索 〜 Elasticsearchとデータ匿名化手法』 『全文検索の探求 Elasticsearch(1) 』: プロジェクト方針およびElasticsearch概要 大量データを検索するサービスでElasticsearchはRDBの代替候補になりうるか?(Elasticsearch vs pg_bigm)』 ←今読んでいる記事 データ匿名化 第1回:匿名化された個人情報とは何なのか データ匿名化 第2回:個人情報は匿名化しても意味がないのではないか? データ匿名化 第3回:個人情報を匿名化するプロセス データ匿名化 第4回:匿名化のために行うデータ項目の一般化とは データ匿名化 第5回:データ匿名化の指標 データ匿名化 第6回:実際の匿名化 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 rakus.hubspotpagebuilder.com ラク スDevelopers登録フォーム https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/ イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! ◆TECH PLAY techplay.jp ◆connpass rakus.connpass.com
アバター