Slide 1

Slide 1 text

比較サイトの検索改善 (SPAからSSRに変換) アウモ株式会社 サーバーサイドエンジニア 天野桂輔

Slide 2

Slide 2 text

• 名前 • 天野 桂輔 • 担当 • サーバーサイドエンジニア • Ruby on Rails、Nuxt.js • 経歴 • 2013- グリー株式会社 • GREE Platform 部に所属 • 2020- アウモ株式会社 • 比較サイト、aRM※の開発担当 ※CRMツール 自己紹介 2

Slide 3

Slide 3 text

aumoはご存知ですか? ⓘ Start presenting to display the poll results on this slide.

Slide 4

Slide 4 text

4 aumoってどんなサービス? 国内最大級のおでかけ情報サービス 1300万 500万 月間ユーザー数 アプリDL数 50万 掲載記事数 総口コミ数 50万 掲載メディア数 500

Slide 5

Slide 5 text

5 aumoってどんなサービス? Web記事 SEOに最適化された コンテンツ制作 Web記事 Web記事 Web記事 位置情報、閲覧傾向を利用 レコメンドシステム App ユーザーの口コミを活用 おでかけCGM Web施設

Slide 6

Slide 6 text

6 Web記事 カテゴリ 技術スタック プログラム言語 / FW Ruby / Ruby on Rails インフラ AWS データベース MySQL, Redis, Memcached, DynamoDB 監視 Datadog, Papertrail, PagerDuty 分析 Bigquery, PoT ※社内分析ツール 検索エンジン ElasticSearch コード管理 GitHub Web記事 SEOに最適化された コンテンツ制作 Web記事

Slide 7

Slide 7 text

7 App Web記事 カテゴリ 技術スタック プログラム言語 / FW Ruby / Ruby on Rails, Swift, Kotlin, Python インフラ AWS データベース MySQL, Redis, Memcached, DynamoDB, FireStore Database 監視 Datadog, Papertrail, PagerDuty, Firebase 分析 Bigquery, PoT ※社内分析ツール 検索エンジン ElasticSearch 機械学習 SageMaker, fastText コード管理 GitHub 位置情報、閲覧傾向を利用 レコメンドシステム App

Slide 8

Slide 8 text

8 Web施設 Web記事 カテゴリ 技術スタック プログラム言語 / FW Ruby / Ruby on Rails, Vue.js, Nuxt.js インフラ AWS データベース MySQL, Redis, Memcached, DynamoDB 監視 Datadog, Papertrail, PagerDuty, Sentry 分析 Bigquery, PoT ※社内分析ツール 検索エンジン ElasticSearch コード管理 GitHub Web施設 ユーザーの口コミを活用 おでかけCGM

Slide 9

Slide 9 text

9 比較サイトとは? Web記事 Web記事 位置情報、閲覧傾向を利用 レコメンドシステム App ユーザーの口コミを活用 おでかけCGM Web施設 Web記事 SEOに最適化された コンテンツ制作 Web記事

Slide 10

Slide 10 text

10 施設情報を提供するサービス 比較サイトとは? • 施設 • 基本情報、写真、口コミ • 検索 • ジャンル×エリア×カテゴリで施設を検索 ホテル グルメ レジャー・観光 チラシ・ショッピング

Slide 11

Slide 11 text

11 構成 フロントエンド バックエンド ELB 同一インスタンスに搭載 サブドメイン

Slide 12

Slide 12 text

12 当初のフロントエンド設計 UXを優先したSPAという方法を採用

Slide 13

Slide 13 text

13 Single Page Application SPA ページ遷移することなく同一のページ内でコンテンツのみ切り替 え サーバー ELB クライアント ①リクエスト ③レスポンス ②コンテンツ生 成 ④JSをブラウザで実行 ※2回目以降は差分のみリクエスト するため処理が早い

Slide 14

Slide 14 text

14 SPA • メリット • 2回目以降は差分のデータのみを要求するため早い • デメリット • 初回のページ読み込みが遅い Single Page Application

Slide 15

Slide 15 text

15 比較サイトの成長に伴い、初回読み込みの遅延が顕著に。。。

Slide 16

Slide 16 text

16 特に、施設の検索が遅い

Slide 17

Slide 17 text

17 検索の課題 • コンテンツ表示までの速度 • 検索エンジン最適化(SEO)対策

Slide 18

Slide 18 text

18 検索の課題 • コンテンツ表示までの速度 • 検索エンジン最適化(SEO)対策

Slide 19

Slide 19 text

19 コンテンツ表示までの速度 検索の課題 • コンテンツ生成が非同期 • レンダリングに時間がかかる

Slide 20

Slide 20 text

20 検索の課題 • コンテンツ表示までの速度 • 検索エンジン最適化(SEO)対策

Slide 21

Slide 21 text

21 検索エンジン最適化(SEO)対策 検索の課題 • コンテンツ生成が非同期で評価できない • Web記事はSEOに強い • ノウハウを共有したい Web記事 SEOに最適化された コンテンツ制作 Web記事

Slide 22

Slide 22 text

22 検索の課題 • コンテンツ表示までの速度 • 検索エンジン最適化(SEO)対策 解決策:SPAからSSR(同期生成)に仕様変更

Slide 23

Slide 23 text

23 Server Side Rendering SSR Webページのレンダリングをブラウザの代わりにサーバ上で行う サーバー ELB クライアント ①リクエスト ③レスポンス ②コンテンツ生 成 ・HTML生成 ・JS実行 ※ Node.js必要 ④コンテンツ表 示 ※画面の表示において有用な アプリケーションの機能

Slide 24

Slide 24 text

24 SSR • メリット • 画面の表示が早い • デメリット • サーバー側の負荷が高い • Node.js サーバー環境が必要 Server Side Rendering

Slide 25

Slide 25 text

25 つまり

Slide 26

Slide 26 text

26 SPAからSSR(同期生成)に仕様を変更することで • コンテンツ表示までの速度 • 検索エンジン最適化(SEO)対策 を改善できる

Slide 27

Slide 27 text

27 仕様変更 • 検索処理 • Vue components 内 mounted 時に実行 • しかも、ジャンル毎に似たような処理がある... mounted () { return this.search() }, search () { const page = this.$route.query.page || 1 : 検索パラメータ設定 : this.searchGourmetAction({ searchQuery, page }) // store経由でAPIリクエスト } 変更前

Slide 28

Slide 28 text

28 Life Cycle NuxtJS nuxt ServerInit Route Middleware fetch() asyncData() created() fetch() mounted() validate() ・初回アクセス時に実行される ・ストアに事前にデータを格納する ☆ page components のみ利用可能 ★ 全ての Vue components で利用可能 ・条件の設定やチェックを行う ・page リダイレクトに利用 ☆ 動的ルーティングのパラメータを検証 Vuex store component data ☆ page レンダリング前にデータを取得 ★ Vue インスタンスが生成されたときに呼び出される ★ Vue インスタンスが生成された後に呼び出される ★ DOM がレンダリングされたときに呼び出される

Slide 29

Slide 29 text

29 Life Cycle NuxtJS nuxt ServerInit Route Middleware fetch() asyncData() created() fetch() mounted() validate() DOM がレンダリングされた後に検索

Slide 30

Slide 30 text

30 Life Cycle NuxtJS nuxt ServerInit Route Middleware fetch() asyncData() created() fetch() mounted() validate() page レンダリング前に検 索

Slide 31

Slide 31 text

31 ① 検索処理の移行 仕様変更 • 検索処理 • page components 内 fetch 時に実行 • page 全てに同様の処理を置くのは微妙なので... async fetch ({ app, route }) { return await Promise.all([ app.$categorySearch({ route }) ]) },

Slide 32

Slide 32 text

32 ② 検索処理の共通化 仕様変更 • plugin 利用 • ジャンル毎の検索処理を共通化 export default ({ store, req }, inject) => { inject('categorySearch', async ({ route }) => { const page = route.query.page || 1 switch (process.host) { case process.env.GOURMET_DOMAIN: : 検索パラメータ設置 : await store.dispatch('gourmetSearch/searchGourmetAction', { searchQuery, page }) break : } }) } ※ ブラウザ環境に帰属するオブジェクト(window, document)にはアクセス不可

Slide 33

Slide 33 text

33 ③ 検索ページ導線を変更 仕様変更 • 検索ページへの遷移処理を修正 • によるページ遷移はクライアント側で実行 • ブラウザをハード再読み込みしてサーバーへリクエスト

Slide 34

Slide 34 text

34 まとめ

Slide 35

Slide 35 text

35 改善項目 • コンテンツ表示までの速度 • 検索エンジン最適化(SEO)対策

Slide 36

Slide 36 text

36 改善項目 • コンテンツ表示までの速度 • リクエストからコンテンツ表示までの速度:55~62%⬇ • 検索エンジン最適化(SEO)対策

Slide 37

Slide 37 text

37 改善項目 • コンテンツ表示までの速度 • 検索エンジン最適化(SEO)対策 • 初回読み込み時に全てのコンテンツを生成

Slide 38

Slide 38 text

38 改善項目 • コンテンツ表示までの速度 • リクエストからコンテンツ表示までの速度:55~62%⬇ • 検索エンジン最適化(SEO)対策 • 初回読み込み時に全てのコンテンツを生成

Slide 39

Slide 39 text

39 学び

Slide 40

Slide 40 text

40 NuxtJS • SSR導入は困難ではない • Node.js サーバー環境を準備 • Nuxt Life Cycle 理解 ※クライアント、サーバーの処理 • 同様の課題があるサービスに有用 • ページ単位で導入も可能

Slide 41

Slide 41 text

41 引き続きより良いサービス作りを心掛けていきます これからもaumoを宜しくお願いしますmm

Slide 42

Slide 42 text

42