TECH PLAY

株式会社ラクス

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

935

こんにちは。シカタ( id:d_shr )です。 先月のことですが、弊社で開催した RAKUS Meetup Osaka #3 で発表しました。 今回は発表内容について書きたいと思います。 発表資料 発表レポート 機能開発を担当している「Mail Dealer」でNode.jsのEOLと格闘した2年間について 以下のようなお話をしました。 Node.jsのバージョンアップができなくなったこと 迫りくるEOL、問題とどのように向き合い・解決しようとしたか Node.jsのバージョンアップを実施したこと ミドルウェア の原因追及が正攻法ですが、アプリケーションの改修による解決したことをお話ししました。 同様の問題に向き合われる方へ参考になれば幸いです。 まだまだ課題は残っており現在調査中ですが、根本的な解決に向けて引き続きチャレンジしていければと思っています。 さいごに、個人的な話です。 弊社主催ではありますが、このような技術イベントでの発表は初めての経験でした。 今回チャレンジしてみて自分のためになることがとても多かったです。 今後は外部のイベントへもチャレンジしてみようと思いました。
アバター
みなさんこんにちは。フジサワです。今回は、 前回の記事 でご紹介いたしました、「 開 ( か ) 発の 未 ( み ) 来に 先 ( せん ) 手をうつプロジェクト(通称:かみせんプロジェクト)」についての途中経過をレポートさせていただきます。 今年度のかみせんプロジェクトでは、大きく以下の2つのテーマ Elasticsearch データ匿名化手法 について検証を進めており、本記事ではElasticsearchの検証について記載いたします。 連載目次 『全文検索 〜 Elasticsearchとデータ匿名化手法』 『全文検索の探求 Elasticsearch(1) 』: プロジェクト方針およびElasticsearch概要 ←今読んでいる記事 大量データを検索するサービスでElasticsearchはRDBの代替候補になりうるか?(Elasticsearch vs pg_bigm)』 データ匿名化 第1回:匿名化された個人情報とは何なのか データ匿名化 第2回:個人情報は匿名化しても意味がないのではないか? データ匿名化 第3回:個人情報を匿名化するプロセス データ匿名化 第4回:匿名化のために行うデータ項目の一般化とは データ匿名化 第5回:データ匿名化の指標 データ匿名化 第6回:実際の匿名化 SQL チューニング以外の手段を 弊社が運営しているサービスの開発では、検索処理のパフォーマンス課題に取り組むことがしばしばあり、検索要件への対応範囲を広げたいと考えています。 複数の動的カラムのデータを横断的に検索したい メールなどの大量の文章データを検索したい など、 SQL チューニングでは一筋縄ではいかないようなシーンにおいて、その他の技術的対応手段としての役割を、Elasticsearchに期待しています。 ※Elasticsearchを検証対象とした詳細な経緯については、 前回の記事 をご覧ください。 全文検索 を使える未来を手に入れる Elasticsearchの検証を進めるにあたり、 バックログ の洗い出しを行いました。 チーム全員がElasticearchに関する知見がない状態からのスタートだったため、まずは以下の書籍を各自読み、Elasticsearchの概要を理解するところから始めました。 Elasticsearch実践ガイド Elasticsearch実践ガイド (impress top gear) 作者: 惣道 哲也 インプレス Amazon Elasticsearchについて詳しく知るための調査を開始 Elasticsearchに関する基礎的な情報や、実際に動作させてみた結果などを Wiki にまとめてナレッジの蓄積を行いました。 PHP で動作するサンプルプログラムを作成し、アプリケーションからのElasticsearchの利用方法の検証なども行なっています。 動作確認は、前述の書籍の他に、以下のような情報も参考にして行いました。 Elasticsearc 公式リファレンス 基本的な API の使い方などは、公式リファレンスをなぞって動作確認しました。 国立情報学研究所作成のGithubリポジトリ Elasticsearchに関して、一通り凝縮してまとめられています。 REST API での検索イメージ それでは、調査結果の一部を抜粋してご紹介いたします。 Elasticsearchの概要 オープンソース の分散 全文検索エンジン 自然言語 で記述された大量の文書データの検索を高速に実行可能 文書データを字句解析し、単語などに分割してインデックス化することで実現している 日本語の字句解析に対応した プラグイン (Kuromoji Analysis Plugin)がある Elastic社 が中心になって開発が進められている 検索エンジン のコア部分は Java 製の検索ライブラリ Apache Lucene が使用されている ドキュメント型データベースで柔軟なデータ構造でデータを保存できる ドキュメント型なので、非正規化した状態でデータを持つ必要がある スケーラブルな構成になっており、事前に最大データ量の検討ができていれば、容易にスケールアウトすることが可能 データの分割単位であるシャード数を事前に定義 ノードを増やすと、新しく増えたノードにシャードが分配されスケールアウトできる ただし、シャード数は後から変更できないため、事前に最大データ量を想定した計画が必要になる トランザクション を持たない(検索・参照に特化) 検索やデータの登録だけでなく、 クラスタ の管理やメンテナンス等の、ほぼ全ての操作が、 REST API を用いて実行できる 検索だけでなく、検索結果の分類や集計なども高速に実行できる。Kibanaとの組み合わせにより、データの傾向やパターン分析などの用途でも用いられる Linux , Windows , Mac 等の各OSに対応しており、公式のDockerイメージなども公開されている 基本動作の確認はDockerコンテナ上で実施 Elasticsearchの活用事例 Elascticsearchの活用事例は、Elastic社の 公式ページ に多数掲載されています。 ここでは、いくつか特徴的な用途で使用している事例を抜粋いたします。 GitHub リポジトリ 、ユーザー、Issue、PR、 ソースコード などの大量の情報を高速に検索できる 日本経済新聞社 日経電子版の記事検索機能で活用 LINE 大量のログデータの一元管理とKibana連携による可視化 かみせんElasticsearch検証チームの様子 開発の未来に先手を打つための議論へ Elasticsearchの概要や機能の理解を経た後、今後どのような検証を行うべきかを、チーム内で議論しました。 その際、キーとなったのは、以下のポイント。 「Elasticsearchを調査・検証することで得られるMinimum Value とはなにか?」 そして、私たちが得た結論は、 『検索機能を有する新規サービスの アーキテクチャ 検討段階で、 RDB だけでなくElasticseachが比較検討材料として挙がる状態を作る』 となりました。 「比較検討材料として挙がる状態を作る」ために、Elasticsearchの得意分野である、 自然言語 で記述された文字列データを持つ、大量データを対象にした検索パフォーマンスを検証を行い、 RDB との比較を行うことにしました。 Minimum Value の検討風景 ※この画像は議論の途中経過のもので、最終的に至った結論ではありません SQL チューニングでは解決できない検索要件が生まれる未来に先手を打つための調査と検証に着手 現在、Minumum Value をアウトプットすべく、Elasticsearchのパフォーマンス検証を行っています。 検証対象のデータには、 Wikipediaの日本語版全データ を採用。 検証開始時点のでドキュメント数:2,339,123 件 下記の環境にストアして検証を実施中 Elasticsearch: Amazon Elasticsearch Service RDB : Amazon RDS for PostgreSQL サーバーのスペック(メモリやノード数など)による変化や検索クエリの当て方など、どのような観点で検証を行うべきかについても議論をしながら進めています。 次回は、検証結果についてレポートさせて頂く予定です。 連載目次 『全文検索 〜 Elasticsearchとデータ匿名化手法』 『全文検索の探求 Elasticsearch(1) 』: プロジェクト方針およびElasticsearch概要 ←今読んでいる記事 大量データを検索するサービスでElasticsearchはRDBの代替候補になりうるか?(Elasticsearch vs pg_bigm)』 データ匿名化 第1回:匿名化された個人情報とは何なのか データ匿名化 第2回:個人情報は匿名化しても意味がないのではないか? データ匿名化 第3回:個人情報を匿名化するプロセス データ匿名化 第4回:匿名化のために行うデータ項目の一般化とは データ匿名化 第5回:データ匿名化の指標 データ匿名化 第6回:実際の匿名化
アバター
初めまして、MasaKuです。 はいくる通信 第1回を担当させていただきます。 はいくる通信はこれから全4回にわたって記事を投稿していきますのでお楽しみに! tech-blog.rakus.co.jp 第1回では、先日、弊社で開催した RAKUS Meetup Osaka の発表内容をもう少し掘り下げた記事を書きたいと思います。 rakus.connpass.com 発表資料は コチラ https://speakerdeck.com/masaku_2019/merumagapei-xin-sabisufalseyue-jing-puroziekuto-merudao-da-lu-xiang-shang-hefalsetiao-zhan speakerdeck.com はじめに:「メールが届かない」にはいろんな理由が 「メールが届かない」のパターン ガイドラインを整理してお客様にご提案する コンテンツチェックをしてお客様に修正をご提案する IPレピュテーションを良いスコアに維持する まとめ 参考サイト はじめに:「メールが届かない」にはいろんな理由が 普段なにげなく利用するメールですが、メールは送信すれば必ず届くとは限らず様々な理由で相手先に届かないことがあります。 そのため、メルマガ配信サービスにとって、どれだけメールを届けられるか(メール到達率)は重要な要素の1つです。 しかし、メルマガ配信サービスはメールを届けることだけが課題ではありません。 配信したメールが迷惑メールとして処理されずにメルマガ読者に読まれることも重要な要素の1つ です。 皆さんも、以下のような経験があるのではないでしょうか? いたって普通の内容のメールが迷惑メールとして処理された 今まで普通にやり取りしていた方のメールが、突然迷惑メールとして処理された 時間をかけて作成したメルマガが迷惑メールになってしまっては本末転倒です。 お客様が望む「メールが届く」とは この課題はメルマガ配信サービスにとって重要な課題ですが、実は配信の仕組みやアプリケーション側の処理だけで解決することが難しい課題なのです。 「メールが届かない」のパターン メールが届かないということでお悩みのお客様には以下のようなパターンがあります。 迷惑メールと判定されるメールになっている 迷惑メールと判定されないように留意しているが、無意識のうちにメール内容が悪くなっている メールの内容も悪くないが、なぜか迷惑メールになってしまう 迷惑メールというと、 公序良俗 に反するような内容のメール(いわゆる スパムメール )を想像すると思いますが、実はそれ以外の理由で迷惑メールと判定される場合があります。 配配メールではそういった課題をクリアするために、いくつかの施策を行っていますので、本日はそちらについてお話したいと思います。 ガイドライン を整理してお客様にご提案する スパムメール などのコンテンツが不正なメールは迷惑メールとして処理されることはご存じかと思います。 しかし、どのようなメールが迷惑メールになるかは、受信サーバごとに設けられたフィルタに依存するため完璧な対策をとることが難しいです。 そこで、配配メールでは少しでも多くのメールをメルマガ読者に届けるための メールを作成するための ガイドライン をお客様向けに展開しています。 メール到達率向上 ガイドライン 例えば、受信サーバ側でブロックされやすいキーワードは避けてメールを作成していただくことや、配信したメールの信頼性を高めるために SPF や DKIM の設定手順を案内する ガイドライン をご提供しています。 この ガイドライン は配配メールの顧客サポート部署が作成しております。 コンテンツチェックをしてお客様に修正をご提案する メール本文内のコンテンツが悪いと迷惑メールとして処理されることを知っていたとしても、意図せず ガイドライン に違反するメールを作成してしまう場合があります。 配配メールでは、メール本文内の情報を解析し、「迷惑メール」扱いになる可能性のあるグレーな内容を検知する仕組みを導入しています。 例えば、メール本文に「現金」と「稼」というキーワードが含まれたメールが配信されると、システム側で迷惑メールの疑いありと判断し本当に スパムメール かを直接チェックしています。 コンテンツチェックのフロー 迷惑メールになる基準は受信サーバ側の基準によるため、 システムが検知したからといって、直ちに スパムメール と判断せずに、顧客サポートチームが直接お客様へご連絡し、メール内容の修正の相談をしています。 地道な作業ではありますが、重要な課題と認識して、課題解決に取り組んでいます。 IPレピュテーションを良いスコアに維持する 最後に、これまでご説明したことがすべて守られているのに迷惑メールとして処理されてしまうことの対策です。 それが、 IPアドレス の信頼性(レピュテーション)という仕様です。 例えば、 スパムメール を頻繁に配信しているサーバは受信サーバ側から迷惑メール配信を行うサーバとして ブラックリスト に登録されてしまいます。 その結果、そのサーバから配信されるメールがブロックされてしまい、普通のメールすら届かないメールサーバになってしまいます。 迷惑メール配信を放置してはいけない理由 配配メールでは、迷惑メールとなるメールを配信し続けているお客様には、警告のご連絡をした後、それでも改善が見られない場合は別のサーバに移動していただく、という施策をおこなっています。 コンテンツ違反顧客の隔離 この施策により、コンテンツが正常なメールを配信されるお客様のメールが利用されるメール配信サーバの IPアドレス の信頼性は高い状態で維持することができます。 まとめ いかがでしたでしょうか? メール配信サービスにおける「 メールを届ける 」とは、単純にメールを届けるだけでなく、メルマガ読者に「 読まれる 」ことが重要です。 そのためには、迷惑メールとして処理されないように様々な工夫が必要であることがご理解いただけたら幸いです。 はいくる通信では、これからもメルマガ配信についての記事を掲載していきます! 次回もどうぞお楽しみに! 参考サイト メルマガ配信・一斉メール配信サービス「配配メール」 https://speakerdeck.com/masaku_2019/merumagapei-xin-sabisufalseyue-jing-puroziekuto-merudao-da-lu-xiang-shang-hefalsetiao-zhan
アバター
はじめに こんにちは、新卒2年目のmrym_618です。 最近、 jQuery でスクロール位置の取得する方法を実装しましたが、なかなかうまくいきませんでしたので、そのときのことを書いていきたいと思います。 はじめに jQueryでスクロール位置を取得する方法 うまくいかなかったこと おわりに jQuery でスクロール位置を取得する方法 jQuery でスクロール位置を取得するには、「scrollTop()」メソッドを使用します。 「scrollTop()」メソッドの記述方法は以下の通りです。 対象要素.scrollTop(); ブラウザ全体のスクロール位置を取得するには対象要素に window を指定します。 $(window).scrollTop(); うまくいかなかったこと 今回は、対象要素に body を指定して実装していました。 すると、Edgeと Safari では、正しい値を取得できていましたが、 Chrome と IE と Firefox では、常に0を取得していました。 原因は、以下のサイトの通りブラウザによって「scrollTop()」メソッドが効くタグが違うことでした。 chaika.hatenablog.com そこで、そのサイトを参考にブラウザごとに対象要素を判定するように実装しました。 var ua = navigator.userAgent; var scrollTag; // Edge, Safariの場合 if(ua.indexOf('Edge') !== -1 || (!window.chrome && 'WebkitAppearance' in document.documentElement.style)) { scrollTag = 'body'; // Chrome, IE, Firefoxの場合 } else { scrollTag = 'html'; } おわりに 今回は、 jQuery でスクロール位置を取得するときに困った話について書きました。もし、同じようなことで困っていれば、この記事が参考になれば幸いです。 また、 jQuery には「scrollTop()」メソッド以外にもブラウザによって挙動が異なるメソッドはあると思うので、 jQuery で実装したときはしっかりマルチブラウザでテストすることを心がけていきたいと思います。 エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 forms.gle イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! rakus.connpass.com
アバター
こんにちは。新卒2年目のbadaikiです。早いもので後輩が配属され、社内の雰囲気がより明るく、より活発になっているように感じます。 目次 目次 はじめに デシジョンテーブルとは デシジョンテーブルの構成 メリット、デメリット 最後に 参考にしたサイト はじめに 今回はテスト手法の デシジョンテーブル について書いていきます。 最近は規模の大きな開発や複雑な仕様の開発を任せていただく機会が増えてきました。そのときに、複数の条件が複雑に絡み合うことによってテストケース作成時に「全パターンを網羅できているのか」が不安になる場面がありました。もちろん100%というのは難しいですが、漏れが起きにくいテストケース、自分が納得のいくテストケースを書くためにはどうすればよいのかを考えました。 まず初めに上記の不安の原因を現状把握も兼ねて分析しました。 同値分割、境界値分析は理解している つもり (単一の条件なら大丈夫) 完成したテストケースを見て網羅できているのかが読み取りにくい 省略したテストケースが本当に省略してよかったのか不安になる(必要なものを誤って省略していないかな…) 上記のような不安の原因になっているものに対して、何か不足している観点がないか、書き方を工夫することで補えないかと考え調べることにしました。そこで着目したのが デシジョンテーブル でした。 デシジョンテーブル とは デシジョンテーブル とは、決定表(JIS X 0125) 1 として規格が定義されています。論理関係を表形式で整理するためのツールで、行方向に条件と動作、列方向にルールを組合せます。プログラムの処理条件やポリシーなどをわかりやすく表現するために利用したり、ソフトウェアのテスト条件を整理するためにも利用されます。 以下を仕様としたときの デシジョンテーブル を例にして考えてみます。 ジムの利用料金の仕様 ・ クーポン持参の場合は10%OFF ・ 平日なら30%OFF ※ 複数の割引は併用できず、よりお得なものが優先される ジム利用料金の デシジョンテーブル デシジョンテーブル の構成 デシジョンテーブル は以下のような要素で構成されています。 条件記述部(condition stub) 条件記述部 考慮すべき条件・原因を列挙する部分です。 動作記述部(action stub) 動作記述部 考慮すべき動作・結果を列挙する部分です。 条件指定部(condition entry) 条件指定部 それぞれの条件・原因を特定の値・意味で指定し、ひとつのルールとして関連付けをします。条件指定部には以下のような書き方をします。 表記 ルールで関連付ける意味 Y(Yes) この行に対応する条件・原因が真であることを意味する N(No) この行に対応する条件・原因が偽であることを意味する 値、語句など この行に対応する条件・原因が記述された値であったり、語句を満たすことを意味する - この行に対応する条件・原因が無関係であることを意味する 動作指定部(action entry) 動作指定部 それぞれの動作・結果を特定の値・意味で指定し、ひとつのルールと関連付けをします。条件指定部には以下のような書き方をします。 表記 ルールで関連付ける意味 X(eXecute) この列に指定された条件・原因の真偽値にすべて適合する場合、この行に対応する動作・結果が生じることを意味する - この列に指定された条件・原因の真偽値にすべて適合する場合、この行に対応する動作・結果が生じないことを意味する 値、語句など この列に指定された条件・原因の真偽値にすべて適合する場合、この行に対応する動作・結果が記述された値であったり、語句を満たすことを意味する 規則 規則 条件・原因の組み合わせと、それに対する動作結果を組み合わせたものです。1つ1つがテストケースになります。 メリット、デメリット メリット 複数の条件が絡みあった組み合わせを明確にすることができる 網羅率が算出できる( = 実施した規則数 / 全規則数) デメリット 順序を考慮できない 規則(テストケース)数が爆発的に増加する 例えば仕様に「月曜日なら女性は50%OFF(祝日は除く)」という仕様を追加します。 ジムの利用料金の仕様 ・ クーポン持参の場合は10%OFF ・ 平日なら30%OFF ・ 月曜日なら女性は50%OFF(祝日は除く) ※ 複数の割引は併用できず、よりお得なものが優先される ジム利用料金の デシジョンテーブル (仕様追加) すると、途端にケース数が増えることがわかります。ですが、曜日と性別が絡んでいる条件を追加したにも関わらず条件記述部は比較的シンプルなまま維持することができ、さらにテーブルになっているため空でテストケースを並べるよりも網羅性の確認が把握しやすいと感じました。 最後に 今回は デシジョンテーブル についてまとめました。 複数の条件が絡むテストケースでは観点がいくつも存在するため網羅できているのかが不安になります。 デシジョンテーブル を利用することで1つ1つの条件に分解し条件記述部を書くことができ、網羅性も確認しやすくなるため有用ではないかと思いました。ただし、テストケースが膨大になってしまうと作業コストがかかってしまうため、1つの画面の一部に用いるなど工夫が必要だと感じました。 テストの精度を高めるために、今後もツールや方法を学習し、実践し努めていきます。 参考にしたサイト softest.jp www.techscore.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 規格検索結果 | 日本規格協会 JSA Group Webdesk ↩
アバター
はじめに こんにちは!今回は6月25日に行われたビアバッシュのご紹介をします。 今回のビアバッシュは翌日に行われたMeetupのリハーサルとLTの2部構成でした。 Meetupについては compass のページをご覧ください。 rakus.connpass.com 対象のMeetupは終了してしまいましたが、定期的にイベントを公開しておりますのでぜひご参加くださいね。 ではでは、LTのご紹介をしていきます。 はじめに 「は」メソッドis何 モナドな約束(Promise) デザインパターン勉強会 PHP7.4 Updates アウトプット駆動読書術実践入門 改善業務「全機能テストの自動化」 おわり 「は」メソッドis何 Scala 好きエンジニアが呟いた、「は」メソッド。「は」メソッドとはなんぞや? といった疑問について Scala の記法の特徴とともに解説してくださいました。 Scala は省略記法も多く、私のように慣れない人から見るとわかりにくい部分もありますが、このように社内で共有してくださるので勉強が捗ります。 モナド な約束(Promise) モナド を通して、 JavaScript のPromiseの使い方や利用目的をわかりやすく解説してくださいました。 JavaScript で非同期処理を記述する際に、Promiseパターンは必ず目にするとは思いますが、初めてのうちはなかなかとっつきにくい部分があると思います。(少なくとも筆者はそうです) 別のもの(今回は モナド )に置き換えて理解の助けとすることを、ぜひ自分の勉強の際にも活かしたいものです。 デザインパターン 勉強会 現在大阪で定期的に行われている社内勉強会、 デザインパターン 勉強会に参加した若手エンジニアが、最近学んだSimple Factoryパターンについて発表してくれました。 ベテラン PHP エンジニアのみなさんによって、若手の知識の幅がどんどん広がってきております。 PHP7.4 Updates PHP おじさん お兄さんが、最新のPHP7.4の機能について紹介してくださいました。 個人的にはTyped Properties のプロパティ型指定に興味を惹かれてしまいます。 ラク スの商材は PHP で作られているものも多いので要チェックですね。 アウトプット駆動読書術実践入門 読書内容について自己学習的な実践を行って内省し、その結果をアウトプットすることでコンパクトに経験学習を行える アウトプット駆動で読書することは、非アウトプット駆動な読書を周回遅れにするほどの自己成長を高める効果がある(かもしれない) 知識を 仕入 れてできる気になったはいいものの、いざ仕事に活かしてみると上手くいかないってことが多々あります。 公開されているスライドで発表者が参考にした情報や書籍も記載されているので、気になる方はどうぞ。 speakerdeck.com 改善業務「全機能テストの自動化」 若手エンジニアが、全機能テストの自動化をpuppeteerを用いて頑張っている話をしてくれました。 リリースサイクルを早めるため、テスト時間を短縮するために自動化に取り組んだ際の手法や難しさについて赤裸々に語ってくれました。 おわり 最近ではビアバッシュの発表者も増加傾向にあり、内容も多岐に渡り非常に聴きごたえがあるものとなっています!! 今後もビアバッシュの内容はブログに掲載していくので、どうぞお楽しみに!!
アバター
はじめに こんにちは、2年目になったyk_itgです。 今回は postgreSQL でindexを利用した時、どれだけ検索速度が上がるのか調べてみよう…としたのですが、うまくindexを使ってもらえませんでした。今回はその時のことを記事にしたいと思います。 なお、この記事では postgreSQL でindexを作成した時のデフォルトであるB-tree indexを使用していることを前提としています。 はじめに 検証バージョン さっそくindexを作ってみた いざ実行 使われない理由 一つ目の理由 二つ目の理由 感想 参考 検証バージョン postgreSQL 11.4 さっそくindexを作ってみた とりあえず、indexを貼るテーブルが必要です。 大量データがないと効果がわからないと思ったので、こちらの記事を参考に100万件のレコードを持つテーブルを作ってみました。 tech-blog.rakus.co.jp CREATE TABLE indexTest ( id integer PRIMARY KEY, name text ) INSERT INTO indexTest (id,name) SELECT i, format('text%s', i) FROM generate_series(1,10000000) as i ; このテーブルにCREATE INDEXしてindexを作ってみます。 CREATE INDEX ON indexTest (id); CREATE INDEX ON indexTest (name); explain_test=# \di List of relations Schema | Name | Type | Owner | Table --------+--------------------+-------+----------+----------- test1 | indextest_id_idx | index | postgres | indextest test1 | indextest_name_idx | index | postgres | indextest (2 rows) いざ実行 では実際にindexを貼ったテーブルに対して検索をかけてみます。 ただ、検索が速くなるといっても目視ではさっぱり違いがわからないのでEXPLAINを使います。 EXPLAINを使うとコストとどんな方法を使って検索しようとしているのか調べることができます。 Indexが利用されている場合には、Index ScanやIndex Only Scanなどのindexを使っていることを示すEXPLAIN 演算子 が実行計画に表示されるはずです。 早速先ほどindexを張ったnameのカラムを検索条件に入れて検索してみます。 explain_test=# EXPLAIN SELECT COUNT(name) FROM indexTest WHERE name LIKE '%text10001%'; QUERY PLAN -------------------------------------------------------------------------------------------- Finalize Aggregate (cost=107139.59..107139.60 rows=1 width=8) -> Gather (cost=107139.38..107139.59 rows=2 width=8) Workers Planned: 2 -> Partial Aggregate (cost=106139.38..106139.39 rows=1 width=8) -> Parallel Seq Scan on indextest (cost=0.00..106138.33 rows=417 width=11) Filter: (name ~~ '%text10001%'::text) (6 rows) あれ?indexが使われていないようですね。 Index Scanではなく、テーブルを順番に見ていくSeq Scanが表示されています。 試しに検索条件をidに変更してみます。 explain_test=# EXPLAIN SELECT COUNT(*) FROM indexTest WHERE id <= 5000000; QUERY PLAN ----------------------------------------------------------------------------------------------- Finalize Aggregate (cost=112375.23..112375.24 rows=1 width=8) -> Gather (cost=112375.01..112375.22 rows=2 width=8) Workers Planned: 2 -> Partial Aggregate (cost=111375.01..111375.02 rows=1 width=8) -> Parallel Seq Scan on indextest (cost=0.00..106138.33 rows=2094672 width=0) Filter: (id <= 5000000) (6 rows) が、やはりindexは使われないようです。 使われない理由 一つ目の理由 一つ目の理由は前方一致以外のLIKEを使って検索しているためです。 B-treeのindexを使用した場合は、文字列の前半についてしか検索を行えません。 なので、前半が検索条件である前方一致の検索ではindexを使用してくれます。 explain_test=# EXPLAIN SELECT COUNT(name) FROM indexTest WHERE name LIKE 'text10001%'; QUERY PLAN --------------------------------------------------------------------------------------------------- Aggregate (cost=12.27..12.28 rows=1 width=8) -> Index Only Scan using indextest_name_idx on indextest (cost=0.43..9.77 rows=1000 width=11) Index Cond: ((name >= 'text10001'::text) AND (name < 'text10002'::text)) Filter: (name ~~ 'text10001%'::text) (4 rows) 実行計画を見てもしっかり Index Only Scanが表示されています。 二つ目の理由 二つ目の理由は検索条件に当てはまる行数が多すぎるためです。 当てはまる行数が多すぎる場合には、indexを使って検索するよりもテーブルを順番にみていくほうが速くなります。 explain_test=# EXPLAIN SELECT COUNT(*) FROM indexTest WHERE id <= 3700000; QUERY PLAN --------------------------------------------------------------------------------------------------------------------------- Finalize Aggregate (cost=110081.60..110081.61 rows=1 width=8) -> Gather (cost=110081.38..110081.59 rows=2 width=8) Workers Planned: 2 -> Partial Aggregate (cost=109081.38..109081.39 rows=1 width=8) -> Parallel Index Only Scan using indextest_pkey on indextest (cost=0.43..105174.50 rows=1562752 width=0) Index Cond: (id <= 3700000) (6 rows) このように検索条件に応じて適切なプランをデータベースは絞り込んでくれます。 感想 indexを使えばどれくらい速くなるのかは検証することができませんでしたが、indexの仕組みや実行計画について触れることが出来ました。 どんどん触れる機会が増えていくと思うので、今後もデータベースの仕組みを学んでいきたいと思います。 参考 [MySQL]WHERE句でLIKEを使っている場合のINDEX | DayByDay PostgreSQLクエリ実行の基礎知識 ~Explainを読み解こう~ 【SQL】インデックスの基本知識まとめ - Qiita B木 - Wikipedia エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 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
アバター
id:radiocat です。 配配メール / クルメル の開発チームでは、我々の取り組みを多くの方々に知ってもらうため、 ブログ連 載プロジェクトを発足させました。写真はキックオフの様子です。まずはメンバー同士で期待値をすり合わせるために ドラッカー 風エクササイズなどを行い、その後みんなで投稿テーマのア イデア を出しました。 キックオフの様子 メール配信を支える技術とノウハウをアウトプットしたい メール配信を取り巻く IT技術 やお客様のビジネスはいまだに日々進化を続けています。 迷惑メールなどでネガティブなイメージがあり利用に消極的な声も聞かれるメール配信ですが、現在でも多くの人がメールを見てショッピングするなどの形で生活へ活用しており、ビジネスにも利用されています。また、メール配信の仕組みは複数の通信キャリアやプラットフォームを跨ぐ複雑なシステム基盤上に構築されており、様々なメールの種類と配信方法で成り立っています。 そんな中で、私たちはお客様のビジネスを成功へ導くために、1通でも多くのメールをお届けできるよう日々努力を続けています。社内でも普段はあまり語られることのないメール配信の裏側ついて配配メール/クルメルの開発を担当しているエンジニアが現場から発信することで、メール配信に興味のある人や普段このブログをご覧頂いているエンジニアのみなさんに少しでも興味をもって頂ければと思い、プロジェクトを発足させました。 まずは第一弾として、4人のメンバーが以下のテーマを1つずつ担当し、投稿記事を検討中です。 メールを到達させる カイゼン 業務の取り組み 6/26の『RAKUS Meetup Osaka カイゼン Night』に登壇させていただいた久山です。 メルマガ配信サービスにおいて、メールを配信できたかどうかは非常に重要です。そのため、配配メールにおいてもメール到達率を向上させるために、いくつかの施策を行っています。しかし、開発者が想定しているメール到達率は、お客様が期待している到達率とギャップがあることに気づきました。 私が担当する記事では、先日発表した『RAKUS Meetup Osaka カイゼン Night』の資料をベースに、 システム開発 者の立場では気づきにくい到達率の本質的な側面についてお話できればと思います。 多種多様なプラットフォームに対応するためのメールの種類 中野です。私がお届けするテーマは「メールの種類について」です。 メール配信には、HTMLメールやテキストメール、多言語メールなどの、様々な種類のメールがあります。ふだん皆さまのお手元に届いているメールの種類とそのメールが送られてくる仕組みを知って頂けるように、わかりやすくてライトな記事を執筆していきます。 皆さまにとって有益な情報をお届けできるようがんばりますので、ご期待ください! メール マーケティング を支える配信方法 ニャンです。2014年に ラク ス ベトナム へ入社しました。 去年の8月に日本に来て配配メールのメンバーと一緒に仕事をしています。 お客様にとって、 マーケティング の方法がいろいろあって、それに合わせた配信方法を選びます。私の投稿では、配配メールでお客様が選べる マーケティング の方法とメールの配信方法をご紹介します。どうぞ楽しみにお待ちください。 キャリアメールの今までと今後 小林です。ディズニーとフュギアをこよなく愛するアラフィフ目前の開発リーダーです。昨今、携帯電話はフューチャーフォンから スマートフォン に変化し、キャリアメールについても変化してきました。 デコメール ・ スマートフォン のHTMLメールなど、今後メールの仕様がどう変わっていくのかを書きたいと考えています。 近日中に順次投稿予定 メール配信に関わる人も、そうでない人も、楽しんで頂けると幸いです。第1回の記事まで、もうしばらくお待ちください。
アバター
はじめに こんにちは。新卒2年目のy_kwmtです。 最近WebStorageに触れる機会があったので、 JavaScript でWebStorageのデータを保存、上書き、削除する方法について説明します。 はじめに WebStorageとは SessionStorageとは LocalStorageとは ローカル環境で実装 最後に 参考にしたサイト WebStorageとは WebStorageとは、ユーザのローカルブラウザにデータを保存する仕組みのことを言います。 WebStorageはSessionStorageとLocalStorageの2種類に分かれます。 SessionStorageとは SessionStorageへ持っている値はウィンドウを閉じるまで有効となります。 別タブ、別ウィンドウへの共有はできません。 LocalStorageとは LocalStorageへ持っている値はウィンドウを閉じたあとでも有効となっています。 別タブ、別ウィンドウへの共有ができます。 ローカル環境で実装 今回はSessionStorageを用いてボタンを押した回数を保存、削除します。 「カウント」ボタンを押してカウントを増やし、「クリア」ボタンを押して、カウントをクリアします。 <!DOCTYPE html> < html > < head > < meta charset = "utf-8" > </ head > < body > < button id = "count" > カウント </ button > < button id = "clear" > クリア </ button > < script > document .getElementById ( "count" ) .onclick = function () { sessionStorage.setItem ( 'count' , eval ( Number ( sessionStorage.getItem ( 'count' )) + 1)) ; } ; document .getElementById ( "clear" ) .onclick = function () { sessionStorage.removeItem ( 'count' ) ; } ; </ script > </ body > </ html > sessionStorage(localStorage).getItemでデータの取得を行います。 「sessionStorage.getItem('count')」で「count」というkeyを持つsessionStorageの value を取得することができます。 sessionStorage(localStorage).setItemでデータの追加、上書きを行います。 「sessionStorage.setItem('count', eval(Number(sessionStorage.getItem('count')) + 1));」で、「count」というkeyを持つsessionStorageの value を1ずつ増やした値を上書きしています。 sessionStorage(localStorage).removeItemでデータの削除を行います。 「sessionStorage.removeItem('count');」で、「count」というkeyを持つsessionStorageのデータを削除します。 ブラウザでの実行の様子がこちらです。 最後に 今回は JavaScript を用いてWebStorageの管理を行いました。 簡易的な実装しかできませんでしたが、次は時間をかけた JavaScript の実装を行い、 JavaScript の理解を深めたいと思います。 参考にしたサイト
アバター
はじめに こんにちは。新卒2年目のaa_cryingです。 最近興味本位でVue.jsについて学習を始めましたので、今回はVue.jsの基礎的な部分について紹介したいと思います。 はじめに Vue.jsとは プログレッシブフレームワークとは Vue.jsの代表的な機能 リアクティブなデータバインディング コンポーネント 高速なレンダリング おわりに 参考にした記事 Vue.jsとは Vue.jsとは、 ユーザーインターフェイス (UI)を構築するための JavaScript の プログレ ッシブ フレームワーク です。 そこで、まずは プログレ ッシブ フレームワーク とは何かについて説明したいと思います。 プログレ ッシブ フレームワーク とは プログレ ッシブ フレームワーク ( Progressive Framework ) とは、Vue.js作者のEvan You氏が提唱する概念です。 JavaScript にはVue.jsの他に jQuery 、React.js、Angular.jsなど様々な フレームワーク が存在します。 実際のプロジェクトではスタート時にこれらの中から フレームワーク を選択し、開発を進めることになります。 しかし、アプリケーションの開発を進めていくと、様々な要件に対応するためにアプリケーションの規模も大きくなっていきます。 そうすると、最初に導入した フレームワーク が合わなくなり、乗り換えるために新しい フレームワーク を模索しなければなりません。 ところがVue.jsは、サポートするツールやライブラリといったエコシステムの存在によって、アプリケーションの要求に柔軟に対応することができます。 このように、 どのような規模、段階のアプリケーションにも対応できる というのが プログレ ッシブ フレームワーク の概念になります。 Vue.jsの代表的な機能 ここではVue.jsの代表的な機能である以下3つの機能について説明していきます。 リアクティブなデータ バインディング コンポーネント 化 高速な レンダリング まずは簡単なコードの例を見ていただければと思います。 <!DOCTYPE html> <!DOCTYPE html> <html> <head> <meta charset= "utf-8" > </head> <body> <div id= "binding" ></div> <div id= "components-button" > <p><count-button></count-button></p> <p><count-button></count-button></p> <p><count-button></count-button></p> </div> <script src= "https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js" ></script> <script> //データバインディングの例 new Vue( { el: '#binding' , template: ` <div> <p><input v-model= "message" ></p> <p> {{ message }} </p> </div> `, data: { message: 'Hello World!' } } ) //componentの例 Vue.component( 'count-button' , { template: '<button v-on:click="increase">{{ count }} 回押しました</button>' , data: function () { return { count: 0 } } , methods: { increase: function () { this .count++; } } } ) new Vue( { el: '#components-button' } ) </script> </body> </html> ブラウザで表示すると以下のようになります。 ブラウザでの実行 Vue.jsを簡単に導入するには cdn.jsdelivr.net からソースを参照する方法があります。 その際は以下のように記述します。 < script src = "https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js" ></ script > vue@2.6.10 と記載するとバージョンを指定して使用することが出来ます。 また、Vue.jsでは、以下のように記述することで、Vue インスタンス とHTML要素との紐づけが可能です。 new Vue( { //<div id="binding"></div>と紐づけ el: '#binding' , // ...略... } ) リアクティブなデータ バインディング el: '#binding' の部分ではデータの更新とDOMの更新を同期的に行っています。 input要素に v-model というディレクティブを使用していますが、これによりリアクティブな入力データの同期を可能にしています。 v-model は、内部的には input 要素に応じて異なるプロパティを使用し、異なるイベントを送り出すという動きをしています。 そのため、v-modelではform要素にある value 等の初期値を無視してしまうので、 JavaScript 側の data オプションの中で初期値を指定する必要があります。 data: { message: 'Hello World!' } 今回は Hello World! を初期値としているため、初期表示ではそのように出力されています。 コンポーネント Vue.componentの部分では、<count-button>という コンポーネント を定義しています。 コンポーネント とは、名前付きの再利用可能なVue インスタンス になります。 new Vue で作成されたルートVue インスタンス 内 (今回はcomponent-button) でカスタム要素として使用できます。 このように再利用できるのはとても便利です。 count-buttonの中で、 v-on:click という記述があると思います。 <button v-on:click= "increase" > {{ count }} 回押しました</button> こちらはVue.js特有の v-on というディレクティブで、DOMイベント発火時の JavaScript の実行が可能になります。 今回の場合は、ボタンをclickすることで increase という関数を呼んでいます。 increase という関数はcountをインクリメントするという内容になっており、 クリックすると ○回押しました の数字がインクリメントされていきます。 また、Vue.jsではイベント修飾子というものを提供しており、それを用いてイベントを制限することもできます。 例えば、以下のように記載するとボタンが1回しか押せなくなります。 <button v-on:click.once= "increase" > {{ count }} 回押しました</button> .onceを付けた結果 他にも様々なイベント修飾子がありますので、詳細は下記リンクを参照してください。 Vue.js公式 - イベントハンドリング 高速な レンダリング Vue.jsでは Virtual DOM を採用しているため、高速な レンダリング (表示処理) を可能としています。 Virtual DOMとは、その名の通り仮想のDOMになります。 実際のDOMと同じ構造の仮想DOMを用意し、仮想DOMに対して処理を行います。そして、その結果生まれた差分だけを実際のDOMに反映します。 この仕組みを用いることで、高速な レンダリング を可能にしています。 おわりに 今回はVue.jsの基礎的な部分について紹介させていただきました。 Vue.jsには今回紹介できなかった便利な機能が沢山ありますので、 次回はもっと掘り下げて紹介していければと思います。 参考にした記事 Vue.js公式ガイド エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 forms.gle イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! rakus.connpass.com
アバター
はじめに こんにちは。新卒2年目のtaku_76です。 今回は Ajax についてざっくりしたことしか分かっていなかったので少し時間を確保してコードから学習することにしました。 はじめに Ajaxとは ローカル環境で実装してみる Ajaxで外部APIへ通信する おわりに 参考にした記事 Ajax とは 以下は Wikipedia の引用です。 Ajax (エイジャックス[1][2]、 アジャックス [3])は、ウェブブラウザ内で非同期通信を行いながら インターフェイス の構築を行うプログラミング手法である[4]。 XMLHttpRequest (HTTP通信を行うための JavaScript 組み込みクラス)による非同期通信を利用し、通信結果に応じてダイナミックHTML (DHTML) で動的にページの一部を書き換えるというアプローチを取る[5]。 Ajax はAsynchronous JavaScript + XML の略で、2005年2月18日に米国のインフォメーションアーキテクトであるJesse James Garrettにより名付けられた[5][6][7]。 他のサイトも見てみましたが、簡単に表すと JavaScript を用いてサーバと非同期通信を行う手法で、 Ajax を用いることでWebページの内容をリロードなしで変更することができます。 ローカル環境で実装してみる まずは、ロジック理解のために通信先をローカルファイルにして実装してみます。 index3.html <!doctype html> <head> <meta charset="utf-8"> <title>Ajaxを利用してローカルの外部ファイルを読み込む</title> <link href="http://code.jquery.com/ui/1.9.2/themes/base/jquery-ui.css" rel="stylesheet" type="text/css"/> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js" type="text/javascript" ></script> <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.9.2/jquery-ui.min.js" type="text/javascript"></script> <script type="text/javascript"> $( function() { $( '#ajax-button' ) .click( function() { $.ajax( { //URL指定 url: 'sample.json', //データ形式指定 dataType : 'json', //通信に成功した場合の処理 success: function( data ) { var message = jsonParser(data); $( '#sample-text' ).html( message ); $( '#sample-text' ).html( obj.code ); $( '#sample-result' ).html( '<hr/><font color="blue">読み込み成功</font><hr/>' ); }, //通信に失敗した場合の処理 error: function( data ) { $( '#sample-result' ).html( '<font color="red">読み込みNG</font>' ); } } ); } ); $('#clear').click(function(){ $( '#sample-text' ).html(''); $( '#sample-result' ).html(''); }); } ); function jsonParser(data) { var message = data.code; message = message + '<br/>'; message = message + data.message; return message; } </script> </head> <body> <h3>Ajaxを利用してjson形式のファイルを読み込みパースする</h3> <p> <input type="button" id="ajax-button" value="読み込む"/> <input type="button" id="clear" value="clear" onclick="OnButtonClick"/> <br/> </p> <div id="sample-result"></div> <div id="sample-text"></div> </body> </html> 以下が今回読み込む sample.json です。 { "code" : "100", "message" : "メッセージ" } Webブラウザ で表示したのち、 読み込む ボタンを押すことによって json ファイルの中身が表示されました。 index3.html Ajax で外部 API へ通信する 以下のコードで外部の API へアクセスすることができます。 今回使用している API は、地域毎の天気予報を Json 形式で返す API です。 無料で会員登録無しで使うことができます。 $( function() { $( '#ajax-button' ) .click( function() { $.ajax( { //天気予報をJson形式で返すAPI url: 'http://weather.livedoor.com/forecast/webservice/json/v1?city=400040',       //通信方法 type:'GET',       //データ形式を指定 dataType : 'json', //通信に成功した場合の処理 }).done(function(data){ alert("成功!"); $( '#sample-text' ).html( data.link ); //通信エラーになった場合の処理 }).fail(function(data){ alert("失敗!"); }); }); }); idが sample-text に Json ファイルの link を表示しています。 おわりに 今回は Ajax について基礎的な学習を行いました。 実践で使うことによってより理解が深まりますので、今回は手間を省くために会員登録の必要のない天気予報の API を利用しましたが、 次は使ってみたい外部の API を探し何か作ってみようと思います。 参考にした記事 http://javatechnology.net/ajax/biginer-start-up/ javatechnology.net エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 forms.gle イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! rakus.connpass.com
アバター
はじめに こんにちは!今回は大阪オフィスで開催された5月ビアバッシュのご紹介です。 令和一発目のビアバッシュは「テーマなし」にして、各々が自由に発表できる形式にしました。 それでは発表内容の一部をダイジェストでお送りいたします。 はじめに ビアバッシュ専用スマホアプリ ITエンジニアは学習しないと死んでしまう生き物 PHPerKaigi2019上映会振り返り 小さいことから始める改善 おわりに ビアバッシュ専用 スマホ アプリ 大阪ではビアバッシュのマンネリ化により、参加者や発表者が固定化するなどの課題を抱えています。 ビアバッシュをもっと楽しむための施策として、リアルタイムに発表にフィードバックできるアプリが登場しました! アプリに「発表内容」を登録しておくと、参加者はアプリを通じて発表内容にコメントやスタンプが送信できます。 このアプリを通じて、ベテランエンジニアだけでなく新人さんも気軽にビアバッシュに参加できるようになればいいですね~ ITエンジニアは学習しないと死んでしまう生き物 弊社エンジニアの"技術力向上"施策のお話です。 我々の業界ではエンジニアは常に技術力を磨かなければいけません。とは言え、やはりモチベーション維持が大変です。。 そんな中、 ラク スでは「学びをアウトプットする場の提供」に力を入れています! 特に最近では、社外向けに自社で Meetup を開催する、外部イベントへ 参加&登壇 するなどの活動を精力的に行っています。 エンジニアがより成長するためにも、今後も様々な施策を実施していきたいですね~ PHPerKaigi2019上映会振り返り PHPerの方にはお馴染み「PHPerKaigi」の上映会を実施したお話です。 本家PHPerKaigiの様子は fortee に動画コンテンツがまとまっているので上映しやすいですね~。 上映会後に発表内容についてみんなで議論することで新たな理解や関連知識を得ることができます。 "良い"技術イベントはみんなでシェアできるといいですね。 小さいことから始める改善 弊社エンジニアによる"改善のしかた"のお話です。 弊社に限らず、どの業界でも「改善」は大事です。一言に「改善」と言っても業務フローの見直しや特定作業の自動化など、挙げればいろいろありそうです。 しかし、まずは「記録する」ことが改善の第1歩。記録することで現状を把握し、チームで相談し合いながらより良くする方法を探すことができます。 今まで行ってきたタスクを記録し、 ECRSの法則 を使って不要なタスクの排除や類似タスクは結合していくといらないことに頭を使わなくてよくなりますb 筆者は ECRSの法則 は知らなかったのでこれを機に勉強してみたいです"φ(゚□゚ (゚□゚ )φ" メモメモ おわりに ビアバッシュも毎回いろんな発表が聞けて楽しいです。 参加してみて「なるほど」と思うことが多いので、個人的な勉強ネタが増えていきます(ただし、消化するのが大変です。。) ぜひ来月も期待して参加します~
アバター
id:radiocat です。毎月お楽しみのエンジニアもくもく勉強会のお知らせです。今回は6/13(木)に開催予定です。 rakus.connpass.com 5月のレポート 前回も様々な技術分野に取り組んでいる方々が参加されました。 PHP 、 Python 、Docker、Vue.jsといったキーワードが複数登場しています。 ブログを書いている人も多く、参加された皆さんの活動の一端を知ることができてエンジニアとして参考になります。また、プログラミングなどの作業の傍らで技術書籍を読んで参考にしている人も多くいらっしゃいました。社内で定期購読している技術雑誌がいくつかあるので、次回は会場内に置いてお読み頂けるようにしたいと考えています。必要に応じて学習の参考にして頂ければと思います。 会場の真ん中に置いてあるお菓子が好評なので引き続きご提供しています。帰宅前に軽くお菓子をつまみながら、もくもくして頂ければと思います。 今月も皆様のご参加をお待ちしております。 6/26(水)にはMeetupも開催予定です。 rakus.connpass.com こちらは参加だけでなくLTも募集しています。残り1枠となっていますので発表してみたいという方はお急ぎください。一般参加枠も募集開始2日目で50%を超えている状況です。ご興味のある方はお早めにご登録ください。もくもく勉強会と合わせてエンジニアの皆様のご参加をお待ちしております。
アバター
最近 RAKUS Meetup 関連の宣伝ばかりしている鈴木( @moomooya )です。今回は ラク ス開発部で実施している取り組みについて複数回にわたって紹介していければと思います。 ラク スの開発部ではこれまで社内で利用していなかった技術要素を自社の開発に適合するか検証し、ビジネス要求に対して迅速に応えられるようにそなえる 「 開 ( か ) 発の 未 ( み ) 来に 先 ( せん ) 手をうつプロジェクト(通称:かみせんプロジェクト)」 というプロジェクトがあります。こちらのプロジェクトの成果について定期的に紹介していきたいと思います。 連載目次 今後投稿される記事にリンクを貼っていきます。 『全文検索 〜 Elasticsearchとデータ匿名化手法』 ←今読んでいる記事 『全文検索の探求 Elasticsearch(1) 』: プロジェクト方針およびElasticsearch概要 大量データを検索するサービスでElasticsearchはRDBの代替候補になりうるか?(Elasticsearch vs pg_bigm)』 データ匿名化 第1回:匿名化された個人情報とは何なのか データ匿名化 第2回:個人情報は匿名化しても意味がないのではないか? データ匿名化 第3回:個人情報を匿名化するプロセス データ匿名化 第4回:匿名化のために行うデータ項目の一般化とは データ匿名化 第5回:データ匿名化の指標 データ匿名化 第6回:実際の匿名化 かみせんプロジェクトでは各チームから有志を募り、先述の課題解決を行う開発部横断プロジェクトとして2017年から運営されています。もちろん業務時間外での取り組み ではなく 、業務時間内での取り組みです(開発部の事業計画にもちゃんと記載されています)。 プロジェクト発足の理由 弊社も長くサービスを提供していますが、長く続くサービスにありがちなのが技術的な陳腐化。ありがたいことに商業的に成功を収めていますが、それゆえになおさら大きな変化を加えにくい状況になりつつあります。 とはいえ年々生産性の高い フレームワーク やライブラリが出てくる中で、変化を避け続けていると競合他社からの追い上げに負けてしまいかねません。5年後、10年後にも優位性を保つためには今後どういったものを取り入れるべきなのかを模索する必要があるという判断により、かみせんプロジェクトが発足することになりました。 なお、かみせんプロジェクトについては以前に取材されたこちらの記事もご参照ください。 マイクロサービスへの挑戦、ラクスが考える技術的負債を返済する最適なタイミング - Qiita:Zine 今期の取り組み かみせんプロジェクトでは一定期間ごとにテーマを変えて検証を進めていますが、今期2019年度上期は「 検索エンジン を用いた 全文検索 」をテーマに進めています。 検索エンジン としてはElasticsearchをターゲットに検証を進めています。Elasticsearch自体は2014年ごろから普及が進んでいましたが、弊社では活用ノウハウを貯めることができていませんでした。 スケーラブルな検索の仕組みは今後データ化される要素が増えて検索対象が大規模化していった際に必要になるものとして長期的な課題となっています。なのでまずは弊社で活用できそうな用途の検証が優先ですが、コンテナベースの クラスタ でスケールが必要になった時の運用ノウハウ蓄積も行なっていこうと考えています。 Elasticsearchは 全文検索 以外にも、Elastic Stack(以前はELK Stackと呼ばれていました)で知られるように分散システムのログ収集、分析、可視化基盤として利用できることや、マッチング度合いをみることができる特徴から今後のサービス展開において応用できる範囲は広いだろうと考えています。 併せて検索の際に必要がないデータや分析に必要ない機微情報を排除し、無用なリスクを低減するためにデータを匿名化する手法も副次的なテーマとして今期の取り組みに含めています。 データがどの程度匿名化されているかを数値化する手法や、データを匿名化するための一般化手法のノウハウを蓄積し、今後 ビッグデータ を利活用する際にもデータを適切に扱えるようになることを期待しています。 今後、定期的に記事を投稿していきますのでよろしくお願いします。 連載目次 今後投稿される記事にリンクを貼っていきます。 『全文検索 〜 Elasticsearchとデータ匿名化手法』 ←今読んでいる記事 『全文検索の探求 Elasticsearch(1) 』: プロジェクト方針およびElasticsearch概要 大量データを検索するサービスでElasticsearchはRDBの代替候補になりうるか?(Elasticsearch vs pg_bigm)』 データ匿名化 第1回:匿名化された個人情報とは何なのか データ匿名化 第2回:個人情報は匿名化しても意味がないのではないか? データ匿名化 第3回:個人情報を匿名化するプロセス データ匿名化 第4回:匿名化のために行うデータ項目の一般化とは データ匿名化 第5回:データ匿名化の指標 データ匿名化 第6回:実際の匿名化
アバター
はじめに こんにちは 入社2年目のEngawaです。タイトルに記載の通り5/18(土)に開催された JJUG CCC 2019 Springに参加してきました。 様々なセッションを見てきましたがその中でも特に印象に残ったものを紹介したいと思います。 http://www.java-users.jp/ccc2019spring/#/ www.java-users.jp ちなみに今回の JJUG には ラク ス社員も登壇しました!! 発表資料は下記からご確認ください。 tech-blog.rakus.co.jp tech-blog.rakus.co.jp 印象に残ったセッション テストエンジニアが教える  JUnit を書き始める前に考えるべきテスト JUnit の書き方についてではなくテストの目的は何か、なぜ早期のテストをするのかなどのテストコード作成の前に考えることについてのセッションでした。 提示された例題からどのようなテストを行うのか実際に考え、それをほかの方と共有することも行いました。大体似たり寄ったりな部分はあったのですが、細かな部分で目の付け所が違い、自分では思いつかないようなテストケースもありました。 テストケースを考える際はどこのテストを行うのか、なぜ行うのかを考えるのは当然だと思っていたのですが、それがどれくらい重要なことなのかを改めて実感しました。 今日から始めるカジュアルな ソースコード 解析 JavaParserという Java の 構文解析 ツールを使って、 ソースコード 解析の入門的な内容から、簡単な実用例までご紹介していくセッションでした。 構文解析 はいままで行ったことがなく、なんとなく敷居が高そうだなくらいの認識でしたが、そこまで難しくないのではないかと印象を受けたので手を出してみるいい機会になったかもしれません。 終わりに 今回初めて JJUG に参加しました。所々理解できなかったこともあり、自身の知識の乏しさを痛感させられました。 これを機にどのような技術が流行っているのかを把握し、今後のために学習を行っていこうと思います。
アバター
RAKUS Meetup のロゴ こんにちは、鈴木です。先日 RAKUS Meetup Tokyo #3 を開催いたしましたので、そちらのイベントレポートを投稿します。 当日の様子 発表の紹介 オブジェクトストレージ導入にあたり、ネットワークエンジニア観点で工夫した事、苦労した事。 売れてる SaaS へのオブジェクトストレージ導入にまつわる泥臭い話 懇親会 次回開催について 当日の様子 RAKUS Meetup Tokyo #3 会場の様子 今回は弊社本社オフィスの セミ ナールームでの開催でした。 当日は雨も降る 悪天候 の中ご参加いただきありがとうございました。RAKUS Meetup Tokyoは毎回雨が降っている気がします。次回は晴れて欲しいですね。 発表の紹介 オブジェクトストレージ導入にあたり、ネットワークエンジニア観点で工夫した事、苦労した事。 弊社インフラエンジニアの永易の発表です。 楽楽精算 にオブジェクトストレージを導入するにあたり考慮した内容を、情報セキュリティの3要素(機密性、完全性、可用性)に沿って発表しました。 プロダクト選定 ハードウェア構成 レプリケーション 設定 バージョニング設定 といった観点について発表しました。 売れてる SaaS へのオブジェクトストレージ導入にまつわる泥臭い話 弊社エンジニアの西角の発表です。 オブジェクトストレージの導入移行時に注意したことや、発生したトラブルについて発表しました。この発表は 先日のJJUG で発表した内容の再演+αになっています。 ファイルストレージをオブジェクトストレージにした際の実装上の影響範囲 20日 かけてデータ移行 移行後に発生したトラブル メンテナンス時間が約90%削減 といった観点について発表しました。 懇親会 お約束の Sushi と Pizza と Beer に加えて RED BULL を用意しました 次回開催について 次回の東京での開催は8月に 「納涼肝試し! WEBサービス 運用の怖い話」 をテーマに開催予定です。 今月6月の後半には募集を開始できると思います。 Connpassのグループ に入っていただけると通知が飛びますのでそちらもよろしくおねがいします。
アバター
はじめに こんにちは、新卒3年目エンジニアのkasuke18です。 私は昨年度の1年間、ビアバッシュ運営委員の一員として抜擢され、活動していました。 運営する中で見つかったとある課題に対して、Webアプリを導入することで カイゼン できそうだということになり、せっかくなのでビアバッシュ運営委員でWebアプリを作ることになりました。 現在その開発の真っ最中ですが、振り返ってみて得られた気付きをご紹介しようと思います。 はじめに やってみての気づき 一人で学習するよりも効率がよい わからないことは全員で考える 作業時間を作るのが大変 まとめ やってみての気づき 一人で学習するよりも効率がよい エンジニアとして自己学習は大切です。とはいえモチベーション維持が難しく、特に新しい技術を学ぶ場合は、一人では資料を見て手を動かすのが限界でマンネリ化してしまうことが多いです。その点、チームで開発することによって相互にレビューできるので、フィードバックをしたりされたりで、一人でやっていては気づけないことにも気づけます。そこからさらに個人的に気になったところを追加で学習することもあります。   わからないことは全員で考える チームメンバー内に詳しい人がおらず、若手メンバーのみで開発しているため、わからないことを相談しようにも全員わからないという場面があります。そのようなときは全員で ベストプラクティスは何だろう? などと考えながら進めています。三人寄れば 文殊 の知恵、というほどうまくいかなくとも全員で考えた結果なので納得感を持って進められます。 作業時間を作るのが大変 手元に開発環境がなければ確認できないので、まとまった時間を作って自宅で作業(実装・レビュー)することが多くなります。とはいえ、他にもやりたいことがあるので、基本的には週末以外ではまとまった時間が取れません。この課題はチームメンバー内でも認識しており、 もくもく勉強会 などの集まれる時間を作ってモブプロ的に開発をすることで、差し戻しの手間を減らし、効率的に進められるように対策しています。 また、個人でも通勤時間中にコードを見るだけなら スマートフォン でもできるので、コードレビューだけやることにしています。先にできることはやっておいて、週末は動作確認と自分の実装に集中して取り組むというようにしています。 まとめ この記事を書くにあたって、個人的に振り返ってみました。 今回の開発で採用した新しい技術は、個人的には一人で学習するにはハードルが高く、おそらく中途半端に学習するだけで終わってしまうことになってしまいそうですが、チームで開発することでそのような状況を回避できました。 毎回このような機会があるわけではないので、次に未経験の技術を学習する際は 勉強会 に参加するなどして、意見交換ができる場に身を置くことを選択肢として考えようと思います。
アバター
こんにちわ @kawanamiyuu です。先日 ブログでお知らせ しました通り、5/18 (土) に開催された JJUG CCC 2019 Spring で登壇してきました。 もうひとりの登壇者である西角さんの登壇レポートはこちら↓ tech-blog.rakus.co.jp 登壇資料 speakerdeck.com 登壇に対する反応 #ccc_i2b hashtag on Twitter ありがたいことに満席でした! 立ち見出てます!! #ccc_i2b #jjug_ccc — yaaka (@yaaka4) 2019年5月18日 人が多すぎてびっくり #ccc_i2b — tea (@tethon) 2019年5月18日 セッションの冒頭で ArchUnit を知っているか問いかけてみたところ、ほぼ全員の方が ArchUnit を知らなかったようでした。 ArchUnit。 初めて聞いた。 — すめらぎ (@sumeragizzz) 2019年5月18日 アーキテクチャ の品質維持関する悩み、ArchUnit の魅力、テストコードのア イデア や事例を共有できる絶好の機会となりました。 アーキテクトの悩み めっちゃわかる 初期の設計がいつの間にか守られなくなる 新規メンバーへの周知ができていない レビュー負担 #ccc_i2b — hituzi3939 (@hituzi3939) 2019年5月18日 commonがいつの間にかcommonでなくなるのは、あるある過ぎる #ccc_i2b #jjug_ccc — yaaka (@yaaka4) 2019年5月18日 ArchUnit、 アーキテクチャ だけじゃなくてアプリケーション・チーム固有のルールも適応度関数化できてだいぶよさそう #ccc_i2b — enk (@enk_enk) 2019年5月18日 普段、ドキュメントに書いてるような開発標準をテストコードで表現して自動チェックできる感じっぽくてよさそう > ArchUnit #jjuc_ccc #ccc_i2b — kntmr (@knt_mr) 2019年5月18日 ArchUnit をぜひプロダクトで活用していただきたい! ArchUnit これは使えそう。 — かわぬん (@chronos2074) 2019年5月18日 セッションは聞いてないんだけど、ArchUnit が良さそうだったなー。一度は評価してみたい。 — Hirotaka Ikoma (@hikoma) 2019年5月18日 さいごに (登壇資料の結びの言葉より) 自動テストで アーキテクチャ の品質を担保しつつ、プロダクト開発を通じて継続的に アーキテクチャ を磨いていくことができるとしたら... どうでしょうか。わくわくしないでしょうか? 😄
アバター
こんにちは。西角(west-c)です。 先日告知がありました通り 、5月18日(土)に開催された JJUG CCC 2019 Spring にて「売れてる SaaS へのオブジェクトストレージ導入にまつわる泥臭い話」というタイトルで登壇しました。 当日発表を見に来てくださった皆様、ありがとうございました。 発表資料 登壇レポート 今年でサービス開始10周年を迎える「 楽楽精算 」にオブジェクトストレージを導入したプロジェクトでの一部始終として、以下のようなお話をしました。 オブジェクトストレージ導入の要因となった楽楽精算が抱えていた課題 クラウド サービス( Amazon S3 など)ではなくオンプレミスのストレージを選択した理由 導入時にアプリケーションの設計面で意識した点 導入後に発生したトラブルから意識すべきだった点 アプリケーションの設計に着手したのはちょうど去年の今頃でしたが、今回の私達のようにオブジェクトストレージへファイルデータ移行を行った事例はあまり見当たらず、手探り状態で設計を進めていたと記憶しています。 今回の登壇が決まってから、同じような課題・悩みを抱える(または今後抱かれるかもしれない)方向けにできる限り生身の情報をお届けしたいと考え、準備を進めました。 拙い発表ではありましたが、発表を聞いてくださったり資料を見てくださった皆様にとって何かしらの知見が得られる内容になれば幸いです。 また、こちらは個人的な話ですが、私にとって今回が初めての外部技術イベントでの登壇でした。 緊張こそしましたが、大きな問題も起きず発表を終えることができて良かったです。 これも資料作成や発表練習に付き合っていただいたり当日応援に来てくれた弊社メンバーの協力のおかげです 🙇 一方で、登壇の場に慣れていないことによる反省点も多々感じましたので、今後もこういった場に参加することで腕を磨いていきたいと思いました!
アバター
こんにちは、MasaKuです。 先日、 PostgreSQL の運用知識学習として以下の書籍を読みました。 gihyo.jp 書籍内で紹介されていた「 パーティショニング 」について、公式ドキュメントに記載されている内容と照らし合わせて、どのようなケースであればパフォーマンスの向上が見込めるのかを確認してみようと思いました。 なお、PostgreSQL11のパーティショニングについては、弊社の アドベントカレンダー にも掲載されておりますので、あわせてご確認いただけると幸いです。 qiita.com テーブルのパーティショニングとは パーティショニングのメリット データの準備 実践 パーティションのキーを用いた検索の場合 全体検索の場合 パーティション分割のキー以外の検索の場合 おわりに 参考サイト テーブルのパーティショニングとは 1つのテーブルを複数のテーブルに分割して管理することをテーブルのパーティショニングといいます。 パーティショニングには以下の種類があります。 ショッピングサイトの購入履歴に関するデータ管理方法を例に説明したいと思います。 レンジ・パーティショニング 指定された範囲の値を基にデータを分散して配置する。 (例: 購入履歴テーブルを1ヶ月単位で分割) レンジ・パーティショニング リスト・パーティショニング テーブルのキーの値を基にデータを分散して配置する (例: 商品カテゴリIDによる分割) リスト・パーティショニング ハッシュ・パーティショニング( PostgreSQL 11 より) データの挿入時にカラムの ハッシュ値 を元に特定の パーティション にデータが偏らないように分散して配置する (例: レコードIDによる分散) ハッシュ・パーティショニング パーティショニングのメリット PostgreSQLの公式ドキュメント ではパーティショニングのメリットを以下のように説明されています 特定の条件下で問い合わせのパフォーマンスが劇的に向上することがあります。 特にテーブル内のアクセスが集中する行の殆どが単一または少数の パーティション に存在している場合がそうです。 パーティショニングはインデックスの先頭にある列の代わりになり、インデックスの大きさを小さくして、インデックスの頻繁に使われる部分がメモリに収まりやすくなるようにします。 問い合わせや更新が一つの パーティション の大部分にアクセスする場合、インデックスやランダムアクセスを使用してテーブル全体にまたがる読み取りをする代わりに、その パーティション への順次アクセスをすることでパフォーマンスを向上させることができます。 一括挿入や削除について、その要件を パーティション の設計に組み込んでいれば、それを パーティション の追加や削除で実現することが可能です。 ALTER TABLE DETACH PARTITIONを実行する、あるいは個々の パーティション を DROP TABLEで削除するのは、一括の操作をするよりも遥かに高速です。 これらのコマンドはまた、一括のDELETEで引き起こされるVACUUMのオーバーヘッドを完全に回避できます。 滅多に使用されないデータを安価で低速なストレージメディアに移行することができます。 今回は、1つ目の利点に着目して動作を確認してみたいと思います。 データの準備 検証のために以下のテーブルを作成しておきます。 -- 商品カテゴリテーブル CREATE TABLE categories( id SERIAL PRIMARY KEY, name TEXT UNIQUE ); -- 商品カテゴリテーブルのサンプルデータ INSERT INTO categories (name) VALUES ( ' 食品 ' ); INSERT INTO categories (name) VALUES ( ' 衣類 ' ); INSERT INTO categories (name) VALUES ( ' 本 ' ); INSERT INTO categories (name) VALUES ( ' コンピュータ ' ); -- 購入位履歴テーブル CREATE TABLE purchase( id SERIAL PRIMARY KEY, category_id INTEGER , name TEXT, date TIMESTAMP DEFAULT NOW()), FOREIGN KEY (category_id) REFERENCES categories(id) ); 購入履歴テーブルのテストデータは過去5年分で合計50万件とします。 -- 購入履歴テーブルのサンプルデータ INSERT INTO purchase (name, category_id, date ) SELECT ' test ' , TRUNC ((RANDOM() * 4 ):: NUMERIC, 0 ) + 1 , ' 2014-01-01 ' :: DATE + (RANDOM() * 1780 ):: INTEGER AS date FROM GENERATE_SERIES( 1 , 500000 ) ; パーティショニングで作成するテーブルについては後述します。 実践 文章内にもありますとおり、特定条件下とは「特にテーブル内のアクセスが集中する行の殆どが単一または少数の パーティション に存在している場合」です。 購入履歴を例にして考えてみたいと思います。 あるサービスでは、5年分の購入履歴を保管しているとします。 そのうち、直近1年の購入履歴からオススメ商品を提示する機能を実装する場合、購入履歴を一つのテーブルで管理するよりも、年単位で分割されたテーブルで管理しておくほうがパフォーマンスは向上するようです。 今回のケースでは date カラム をキーとするレンジ・ パーティション を行います。 CREATE TABLE purchase_range( id SERIAL, category_id INTEGER , name TEXT, date TIMESTAMP DEFAULT NOW(), FOREIGN KEY (category_id) REFERENCES categories(id) ) PARTITION BY RANGE ( date ); CREATE TABLE purchase_range_y2014 PARTITION OF purchase_range FOR VALUES FROM ( ' 2014-01-01 00:00:00 ' ) TO ( ' 2014-12-31 23:59:59 ' ); CREATE TABLE purchase_range_y2015 PARTITION OF purchase_range FOR VALUES FROM ( ' 2015-01-01 00:00:00 ' ) TO ( ' 2015-12-31 23:59:59 ' ); CREATE TABLE purchase_range_y2016 PARTITION OF purchase_range FOR VALUES FROM ( ' 2016-01-01 00:00:00 ' ) TO ( ' 2016-12-31 23:59:59 ' ); CREATE TABLE purchase_range_y2017 PARTITION OF purchase_range FOR VALUES FROM ( ' 2017-01-01 00:00:00 ' ) TO ( ' 2017-12-31 23:59:59 ' ); CREATE TABLE purchase_range_y2018 PARTITION OF purchase_range FOR VALUES FROM ( ' 2018-01-01 00:00:00 ' ) TO ( ' 2018-12-31 23:59:59 ' ); -- 購入履歴テーブルサンプルデータ(パーティション) INSERT INTO purchase_range (name, category_id, date ) SELECT ' test ' , TRUNC ((RANDOM() * 4 ):: NUMERIC, 0 ) + 1 AS category_id, ' 2014-01-01 ' :: DATE + (RANDOM() * 1780 ):: INTEGER AS date FROM GENERATE_SERIES( 1 , 500000 ) ; パーティション のキーを用いた検索の場合 まずは、2017年12月の購入履歴の件数を取得する SQL を実行した結果を見てみましょう。 -- 単一テーブルで管理されている場合 explain analyze select count (*) from purchase where date > ' 2017-12-01 ' and date < ' 2017-12-31 ' ; QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------------------------------- Finalize Aggregate (cost= 6114 . 90 .. 6114 . 91 rows = 1 width= 8 ) (actual time= 125 . 218 .. 125 . 218 rows = 1 loops= 1 ) -> Gather (cost= 6114 . 69 .. 6114 . 90 rows = 2 width= 8 ) (actual time= 120 . 538 .. 125 . 274 rows = 3 loops= 1 ) Workers Planned: 2 Workers Launched: 2 -> Partial Aggregate (cost= 5114 . 69 .. 5114 . 70 rows = 1 width= 8 ) (actual time= 96 . 651 .. 96 . 652 rows = 1 loops= 3 ) -> Parallel Seq Scan on purchase (cost= 0 . 00 .. 5108 . 41 rows = 2513 width= 0 ) (actual time= 0 . 036 .. 96 . 162 rows = 2053 loops= 3 ) Filter: (( date > ' 2017-12-01 00:00:00 ' ::timestamp without time zone) AND ( date < ' 2017-12-31 00:00:00 ' ::timestamp without time zone)) Rows Removed by Filter: 100529 Planning Time: 0 . 215 ms Execution Time: 125 . 323 ms -- パーティションで分割しているテーブルの場合 explain analyze select count (*) from purchase_range where date > ' 2017-12-01 ' and date < ' 2017-12-31 ' ; QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------------------------- Aggregate (cost= 26 . 09 .. 26 . 10 rows = 1 width= 8 ) (actual time= 0 . 007 .. 0 . 007 rows = 1 loops= 1 ) -> Append (cost= 0 . 00 .. 26 . 07 rows = 5 width= 0 ) (actual time= 0 . 004 .. 0 . 004 rows = 0 loops= 1 ) -> Seq Scan on purchase_range_y2017 (cost= 0 . 00 .. 26 . 05 rows = 5 width= 0 ) (actual time= 0 . 003 .. 0 . 003 rows = 0 loops= 1 ) Filter: (( date > ' 2017-12-01 00:00:00 ' ::timestamp without time zone) AND ( date < ' 2017-12-31 00:00:00 ' ::timest amp without time zone)) Planning Time: 0 . 667 ms Execution Time: 0 . 034 ms 実行時間は パーティション で分割しているテーブルの方が短くなるという結果になりました。 日時で パーティション を分割しているため、対象外の期間のレコードにはアクセスされないためパフォーマンスが向上しました。 全体検索の場合 今度は、全データの件数を取得する場合を考慮してみました。 -- 単一テーブルで管理されている場合 explain analyze select count (*) from purchase; QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------------- Finalize Aggregate (cost= 6789 . 38 .. 6789 . 39 rows = 1 width= 8 ) (actual time= 274 . 970 .. 274 . 970 rows = 1 loops= 1 ) -> Gather (cost= 6789 . 17 .. 6789 . 38 rows = 2 width= 8 ) (actual time= 273 . 169 .. 275 . 097 rows = 3 loops= 1 ) Workers Planned: 2 Workers Launched: 2 -> Partial Aggregate (cost= 5789 . 17 .. 5789 . 18 rows = 1 width= 8 ) (actual time= 252 . 091 .. 252 . 092 rows = 1 loops= 3 ) -> Parallel Seq Scan on purchase (cost= 0 . 00 .. 5268 . 33 rows = 208333 width= 0 ) (actual time= 0 . 016 .. 105 . 048 rows = 166667 loops= 3 ) Planning Time: 0 . 135 ms Execution Time: 275 . 149 ms -- パーティションで分割しているテーブルの場合 explain analyze select count (*) from purchase_parent; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------- Finalize Aggregate (cost= 8690 . 90 .. 8690 . 91 rows = 1 width= 8 ) (actual time= 429 . 425 .. 429 . 425 rows = 1 loops= 1 ) -> Gather (cost= 8690 . 68 .. 8690 . 89 rows = 2 width= 8 ) (actual time= 429 . 415 .. 429 . 608 rows = 3 loops= 1 ) Workers Planned: 2 Workers Launched: 2 -> Partial Aggregate (cost= 7690 . 68 .. 7690 . 69 rows = 1 width= 8 ) (actual time= 406 . 901 .. 406 . 901 rows = 1 loops= 3 ) -> Parallel Append (cost= 0 . 00 .. 7169 . 85 rows = 208334 width= 0 ) (actual time= 0 . 018 .. 269 . 589 rows = 166667 loops= 3 ) -> Parallel Seq Scan on purchase_y2017 (cost= 0 . 00 .. 1259 . 81 rows = 60481 width= 0 ) (actual time= 0 . 015 .. 90 . 205 rows = 102817 loops= 1 ) -> Parallel Seq Scan on purchase_y2015 (cost= 0 . 00 .. 1259 . 19 rows = 60419 width= 0 ) (actual time= 0 . 017 .. 112 . 477 rows = 102713 loops= 1 ) -> Parallel Seq Scan on purchase_y2016 (cost= 0 . 00 .. 1257 . 65 rows = 60365 width= 0 ) (actual time= 0 . 016 .. 18 . 776 rows = 34207 loops= 3 ) -> Parallel Seq Scan on purchase_y2014 (cost= 0 . 00 .. 1255 . 53 rows = 60253 width= 0 ) (actual time= 0 . 014 .. 61 . 613 rows = 51215 loops= 2 ) -> Parallel Seq Scan on purchase_y2018 (cost= 0 . 00 .. 1096 . 00 rows = 52600 width= 0 ) (actual time= 0 . 019 .. 76 . 853 rows = 89420 loops= 1 ) Planning Time: 0 . 162 ms Execution Time: 429 . 668 ms ある意味予想通りでしたが、実行時間はパーティショニングしているテーブルのほうが長くなりました。 テーブルを分割しているために、本来一度で完了するシーケンシャルスキャンが パーティション の数だけ実行されるため、パフォーマンスが劣化したと思われます。 購入履歴を検索する、ということに主眼を置く場合は、運用方法次第ではパーティショニングが必ずしも適切ではない場合もあるので注意が必要です。 パーティション 分割のキー以外の検索の場合 最後に、 パーティション 分割に利用したキー以外のカラムを絞込み条件にした場合のパフォーマンスを確認してみます。 今回はカテゴリIDを対象にした検索を行ってみたいと思います。 -- 単一テーブルで管理されている場合 explain analyze delete from purchase where category_id = 1378 ; QUERY PLAN ------------------------------------------------------------------------------------------------------------- Delete on purchase (cost= 0 . 00 .. 7031 . 81 rows = 1 width= 6 ) (actual time= 87 . 803 .. 87 . 803 rows = 0 loops= 1 ) -> Seq Scan on purchase (cost= 0 . 00 .. 7031 . 81 rows = 1 width= 6 ) (actual time= 87 . 801 .. 87 . 801 rows = 0 loops= 1 ) Filter: (category_id = 1378 ) Rows Removed by Filter: 307745 Planning Time: 0 . 062 ms Execution Time: 87 . 829 ms -- パーティションで分割しているテーブルの場合 explain analyze delete from purchase_range where category_id = 1378 ; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------- Delete on purchase_range (cost= 0 . 00 .. 7869 . 12 rows = 5 width= 6 ) (actual time= 103 . 825 .. 103 . 826 rows = 0 loops= 1 ) Delete on purchase_range_y2014 Delete on purchase_range_y2015 Delete on purchase_range_y2016 Delete on purchase_range_y2017 Delete on purchase_range_y2018 -> Seq Scan on purchase_range_y2014 (cost= 0 . 00 .. 1614 . 14 rows = 1 width= 6 ) (actual time= 22 . 576 .. 22 . 576 rows = 0 loops= 1 ) Filter: (category_id = 1378 ) Rows Removed by Filter: 76811 -> Seq Scan on purchase_range_y2015 (cost= 0 . 00 .. 1612 . 55 rows = 1 width= 6 ) (actual time= 21 . 112 .. 21 . 112 rows = 0 loops= 1 ) Filter: (category_id = 1378 ) Rows Removed by Filter: 76844 -> Seq Scan on purchase_range_y2016 (cost= 0 . 00 .. 1627 . 21 rows = 1 width= 6 ) (actual time= 20 . 850 .. 20 . 850 rows = 0 loops= 1 ) Filter: (category_id = 1378 ) Rows Removed by Filter: 77537 -> Seq Scan on purchase_range_y2017 (cost= 0 . 00 .. 1603 . 49 rows = 1 width= 6 ) (actual time= 21 . 146 .. 21 . 146 rows = 0 loops= 1 ) Filter: (category_id = 1378 ) Rows Removed by Filter: 76279 -> Seq Scan on purchase_range_y2018 (cost= 0 . 00 .. 1411 . 74 rows = 1 width= 6 ) (actual time= 18 . 105 .. 18 . 106 rows = 0 loops= 1 ) Filter: (category_id = 1378 ) Rows Removed by Filter: 67099 Planning Time: 0 . 376 ms Execution Time: 103 . 901 ms 多少の差があるもののそこまで大きな差がないという、少し意外な結果となりました。 というのも、今回作成したサンプルデータは日付でパーティショニングしているため、カテゴリIDで絞り込んだ場合は分散配置しているテーブルすべてをチェックしなければならなくなります。 そのため、先ほどの全体検索と同程度のパフォーマンスになると思っていました。 パーティション で分割されているテーブルの数や、1テーブルに格納されているレコードの量によって差が出るのではないでしょうか。 おわりに パーティショニングといっても、データ管理の 銀の弾丸 というものではなく、場合によってはパフォーマンスが劣化する場合があることがわかりました。 今回はレンジ パーティション を例にしましたが、実際のサービスがどのように運用されていくかを考慮することで、どのように パーティション を分割すべきかが見えてくるのではないでしょうか。 (もしくは、 パーティション 分割する必要が無いことも) その他にも、継承パーティショニングの検証や、高負荷状態でのパフォーマンスなど、検証してみたいことがありましたが、その辺はまた別の機会にしたいと思います。 参考サイト [改訂新版]内部構造から学ぶPostgreSQL 設計・運用計画の鉄則:書籍案内|技術評論社 第1回「テーブル・パーティショニングが大幅アップデート」 | NTTデータ先端技術株式会社 PostgreSQL 11先行紹介 - パーティション機能のさらなる改善 | NTTテクノクロスブログ PostgreSQL11のパーティショニングを試してみる - Qiita 5.10. テーブルのパーティショニング エンジニア 中途採用 サイト ラク スでは、エンジニア・デザイナーの 中途採用 を積極的に行っております! ご興味ありましたら是非ご確認をお願いします。 https://career-recruit.rakus.co.jp/career_engineer/ カジュアル面談お申込みフォーム どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。 以下フォームよりお申込みください。 forms.gle イベント情報 会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください! rakus.connpass.com
アバター