UGA Boxxx

つぶやきの延長のつもりで、知ったこと思ったこと書いてます

【Elasticsearch】Multi-match queryのtype

以前、ElasticsearchのMulti-match queryを使ってみた

uga-box.hatenablog.com

これの用途として、例えば"東京"のつもりで「to」と入力された時に、完全一致が一番スコアが高く、前方一致するものがアナライザーに即して順次ぶら下げたいというときに

このようにkeywordに対してブーストをかけて検索していた

      "query": "to", 
      "fields": [ 
          "city.keyword^2",
          "text.keyword^2",
          "city",
          "text"
        ],
       "type": "best_fields",

しかし、次に"東京 新宿"のつもりで「tokyo shinju」と入力された時に、「tokyo」は完全一致のみだが、「shinju」は先ほどと同じように完全一致が一番スコアが高く、前方一致するものが次にくるようにするクエリをどうするか

ちょっと複雑になりそうで考え直した

ここで、Multi-match queryのtypeをデフォルトのbest_fieldsにしていたのだが、他の使い方について調べてみた

www.elastic.co

type 概要
best_fields (デフォルト)任意のフィールドに一致するドキュメントを検索し、_scoreが最も高いものを使用する
most_fields 任意のフィールドに一致するドキュメントを検索し、各フィールドの_scoreを組み合わせる
cross_fields フィールドを1つの大きなフィールドであるかのように、同じアナライザーで処理する。任意のフィールドで各単語を検索する。
phrase 各フィールドでmatch_phraseクエリを実行し、_scoreが最も高いものを使用する
phrase_prefix 各フィールドでmatch_phrase_prefixクエリを実行し、_scoreが最も高いものを使用する
bool_prefix 各フィールドにmatch_bool_prefixクエリを作成し、各フィールドの_scoreを結合する

最後のmatch_bool_prefixクエリが気になって調べたらドンピシャで求めているものだった

match_bool_prefixクエリ

Match boolean prefix query | Elasticsearch Guide [7.x] | Elastic

以下のようなクエリを書くと

GET /_search
{
  "query": {
    "match_bool_prefix" : {
      "message" : "quick brown f"
    }
  }
}

次のクエリと同等のことをおこなってくれる

GET /_search
{
  "query": {
    "bool" : {
      "should": [
        { "term": { "message": "quick" }},
        { "term": { "message": "brown" }},
        { "prefix": { "message": "f"}}
      ]
    }
  }
}

なので、クエリはbool_prefixを使って以下とするのがよさそう

      "query": "tokyo shinju", 
      "fields": [ 
          "city",
          "text",
        ],
       "type": "bool_prefix",

ということがわかった

他参考

https://christina04.hatenablog.com/entry/elasticsearch-multi-match-query

【Safari】iOS15で画面下部に固定ナビゲーション「タブバー」が配置される

iOS15で画面下部に固定のナビゲーション「タブバー」が配置されるらしい

www.apple.com

f:id:uggds:20210613170035p:plain:w300

ブラウザで開いているタブを保存できて、iPhoneiPadMacのどれからでもアクセスできるようになるとのことだが、ほとんどのサイトでこの位置にCTAがあるためちょっと話題になっている

回避策として、padding-bottom: env(safe-area-inset-bottom)を使うとよいという話がある

env() は CSS の関数で、ユーザーエージェントが定義した環境変数の値を、 var 関数やカスタムプロパティと同じ方法で CSS に挿入するために使用することができます。異なる点は、ユーザーが定義しているのではなくユーザーエージェントが定義しているものであること、カスタムプロパティは宣言されている要素のスコープであるのに対し、環境変数は文書でグローバルなスコープであることです。

env() - CSS: カスケーディングスタイルシート | MDN

これはiPhoneXがでたときのSafeAreaの対応がキーになりそう

webkit.org

他参考

https://web-design-textbook.com/recipe/iphone-design.html

【GCP】BigQueryとCloud SQL のテーブル結合

BigQueryとCloud SQL のテーブルで結合したい

結論、データ移行しなくても結合することができることがわかったので軽く手順をメモする

BQの管理から「データを追加」 >「外部データソース」を選択する f:id:uggds:20210613121346p:plain:w300

でてきた入力フォームに外部データソースの接続情報を入力すると以下のようにデータセットとして表示される

f:id:uggds:20210613121814p:plain:w300

クエリは以下のよう感じになる

SELECT * FROM EXTERNAL_QUERY("projects/my-project/locations/asia-northeast1/connections/backend-db-postgres", "SELECT * FROM MY_SCHEMA.TABLE_NAME;");

料金

ドキュメントによると

cloud.google.com

外部データソースに対してクエリを実行する場合、クエリによって読み取られたバイト数に基づいて料金が請求されます。外部データが Cloud Storage などの別の Google Cloud プロダクトに保存されている場合は、そのプロダクトのストレージ料金も適用されます。

とあるので、Cloud SQLとの外部接続だろうがクエリ実行する際に読み取られるバイト数が料金請求される模様
※処理されるクエリデータは毎月 1 TB まで無料なのはうれしい

ただし、ストレージ料金はCloud SQLのストレージ料金で請求される

【GCE】Springを起動したらmemory-calculatorでエラーが発生する

Spring Batchでバッチアプリケーションをつくり、Spring Bootのmavenプラグインを使ってdockerイメージを作る

それをGCEのContainer Optimized OS上で実行しようとしたとき次のようなエラーがでて処理が終了してしまった

"JVM DNS caching disabled in favor of link-local DNS caching "
"$BPI_APPLICATION_PATH must be set "
"[31;1mERROR: [0mfailed to launch: exec.d: failed to execute exec.d file at path '/layers/paketo-buildpacks_bellsoft-liberica/helper/exec.d/memory-calculator': exit status 1

最後の1行からmemory-calculatorが何か失敗した模様

memory-calculatorJavaのコンテナのメモリ割り当てを自動でおこなってくれる機能

根本原因は不明だが、Spring Bootのmemory-calculatorとContainer Optimized OSの相性が悪いのかと推測し、builderを以下に差し替えてみる

github.com

pom.xml

     <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
          <image>
            <name>asia.gcr.io/my-app/${project.artifactId}</name>
            <builder>gcr.io/buildpacks/builder:v1</builder>
          </image>
          <skip>false</skip>
        </configuration>
      </plugin>

実は、上のbuilderはmemory-calculatorの機能がはいっていないみたいなので、普段なら使わないほうがよい?のだが、今回はその機能がないことが幸いしてアプリが問題なく動作させることができた

他参考

https://github.com/making/blog-handson/blob/master/memory-calculator.md

【Webパフォーマンス】Lighthouse 8

Lighthouseのバージョン8.0がリリースされ、PageSpeed InsightsやChrome Canaryで利用できるらしい

このバージョンではJavaScriptの分析ができるようになっていて、視覚的にJavaScript の容量とかカバレッジを確認できるとのこと

そして、モジュールサイズと実行範囲に基づいてトリミングすることもできるみたい

また、スコアのウェイトが変更された模様

v6,v7
f:id:uggds:20210606162418p:plain

v8
f:id:uggds:20210606162439p:plain

指標 v6,v7 v8
FCP 15% 10%
SI 15% 10%
LCP 25% 25%
TTI 15% 10%
TBT 25% 30%
CLS 5% 15%

CLSに重みがついたみたい

【デザイン】Material You

5月19日に開催されたオンラインイベント「Google I/O 2021」をみていて、Googleの新しいデザインフレームワーク「Material You」というのを知った

material.io

簡単に言うとアプリのパーソナライズ化と理解した

ユーザーが実用的な機能の次に求めるのは、感情を呼びおこす体験であると考え、ユーザー自身が使いやすい快適なデザインを採用したり、個性を表現したりできるようにするフレームワークとのこと

具体的には

  • 壁紙から導出した「マテリアル パレット」でアプリの配色を調整する
  • 新しい画面サイズ、デバイスの種類、入力方法、およびコンテキストにモーションをつけてスムーズに適応させる 
  • アクセシビリティ向上のため、コントラスト、サイズ、線幅の制御をカスタマイズ可能にする

サイトへの適用

マテリアルデザインのように、ガイドラインに沿ってデザインするとよさそうとはまだ思えなかった

パーソナライズ化は理解したが

例えば、Webサイトになると壁紙から配色を〜っていうのはできないので、こちらで配色を複数用意するのか?とか、文字サイズを変えられるようにする?(昔あったような)とか余計な機能が増えそう

実際それがニュースタンダードになる世界が想像できないのでしばらく観察していきたい

【GCE】Springのログがでない

GCE上でSpringバッチを動かそうとしたが、おそらく何らかのエラーが発生して処理が終了していた

原因を調査するためにCloud Loggingをみてみたが、Springバッチが起動した形跡(あのアスキーアートなど)がなく、インスタンス削除が行われた形跡があった

となるとdocker imageが壊れているか、とにかくSpringバッチ側の問題ではないだろうと思っていたが全く原因が不明だった

もう少し調べみるとバッチではBigQueryにテーブルを作る処理があるのだが、そのテーブルが作成されているのでSpringは起動していることがわかった

そうなると、出ていないだけで実際は起動していることになるので、なぜかSpringのログがでていない問題とわかった

結果的に

結果的に、SpringのログをLoggingに送信する前に、自動インスタンス削除が走っていたことが原因だった

公式ドキュメントは見つからなかったが、GCEのインスタンスにFluentdがデプロイされ、FluentdではCloud Loggingにログを送信している仕組みらしいので

FluentdからCloud Loggingにログを送信する前にインスタンスが削除されると、そのログはロストしてしまう

これが原因だった

なので、Springのmainの実行を2分ほどスリープさせてから行うようにしてみたところログがCloud Loggingに表示された

    try {
      final int interval = 120;
      TimeUnit.SECONDS.sleep(interval);
      System.out.println("Waiting...");
    } catch (InterruptedException e) {
      System.err.println(e.getMessage());
      throw new RuntimeException(e);
    }
    SpringApplication.run(MyBatchApplication.class, args);