Redash 上で桁数が多い数値を表示すると発生する誤差について調べた

久しぶりの記事もやはり Redash 関連でした。

結論を先に(個人の感想・意見です)

  • Redash の UI 上で 9007199254740991 を超える数値を扱いたい場合は、精度が下がることを許容するか文字列として扱う
  • これは JavaScript の仕様によるものなので、当面は Redash のバージョンアップだけで対応される可能性は低い
  • Redash についての質問はぜひ Redash 日本語フォーラム で!

きっかけ

このツイートを目にしたことがきっかけでした。

いったん「redash じゃなくて Redash」については気にしないことにしましょう。

以前も似たようなツイートを見た覚えがあるのですが、ちょっと気になったので調べてみたくなりました。

再現してみる

環境について

データソースは SQLite 以外に MySQL 5.7 や PostgreSQL 9 でも確認し、同様の現象が発生することを確認していますが、この記事では手元の環境で検証したいので SQLite を使用して検証をした結果について書いていきます。

また、Redash についても 7.0.0, 8.0.0 で同様の現象が発生していることを確認していますが、こちらも手元の環境に合わせて 9.0.0-beta を使用しています。

再現手順

実行したクエリーは以下です。

select 12345678901234567890 foo;

クエリの実行結果を見ると、下3桁が違っていることに気づきます。

f:id:ariarijp:20201124222325p:plain

17桁にしてみても、まだ誤差がある。

select 12345678901234567 foo;

f:id:ariarijp:20201124222652p:plain

16桁にしてみると、どうやら問題なさそう。

select 1234567890123456 foo;

f:id:ariarijp:20201124223049p:plain

ツイートされていた現象は17桁以上の数値を扱おうとすると遭遇するようです。

原因を考える

どこで誤差が発生しているのかを考えて、ざっくり以下のようにわけてみました。

  • Redash のフロントエンド(HTML / JavaScript)
  • Redash のサーバーサイド/API(Python)
  • Redash のワーカー(Python)
  • データソース(接続先による)

ここまでの調査で以下の仮説があったので、フロント寄りをみていくことにします。

  • 複数のデータソースで現象を確認しているので、データソースよりもフロント寄りで起きていそう
  • 大きな値ではあるが、Python で扱えない桁数ではなさそう
    • (17桁でも起きるので Python の int の最大値 2**63 - 1 は関係なさそう)

調査してみる

調査については以下のクエリーを使っていきます。

select 12345678901234567 foo;

サーバーサイドをみる

Redash のサーバーサイドの処理はほとんどが REST(RESTish?) API になっているため、クエリーの結果も API が返します。まずはそのレスポンスをみてみました。

確認手順の詳細は割愛しますが、以下が API から取得できる JSON です。

{
    "query_result": {
        "id": 18,
        "query_hash": "13f6db1bd3a5470f7d0641d1a7a380eb",
        "query": "select 12345678901234567 foo;\n",
        "data": {
            "columns": [
                {
                    "name": "foo",
                    "friendly_name": "foo",
                    "type": "integer"
                }
            ],
            "rows": [
                {
                    "foo": 12345678901234567
                }
            ]
        },
        "data_source_id": 1,
        "runtime": 0.00493335723876953,
        "retrieved_at": "2020-11-24T13:44:31.532Z"
    }
}

API12345678901234567 という値を返してくれているようなので、API より手前側で何かが起きているというのは正しそうです。

フロントエンドをみる

ふと、12345678901234567JavaScript は数値として扱えるのかなと思ったので、開発者ツールのコンソールで試してみました。

f:id:ariarijp:20201124225000p:plain

入力に対し、結果として表示される値が変わっていますね。このあたりにヒントがありそうです。

もう少し調べてみる

MDN を参照してみたところ「Number の整数の範囲」という項目がありました。おそらくこれが原因を表しているのだと思います。

developer.mozilla.org

JavaScript で扱えるの最大値は 9007199254740991 ということと、JSON9007199254740991 を超える値をデシリアライズすると信頼できない値になることについて触れられているので、試してみましょう。

select
    9007199254740991 foo
    , 9007199254740992 bar
    , 9007199254740999 baz;

f:id:ariarijp:20201124230233p:plain

9007199254740992 にしても結果は変わらないようにみえますが、9007199254740999 は結果が 9007199254741000 となっていて 1 多いので、信頼できないといえそうです。

JavaScript の Number の最大値から離れれば離れるほど、かつ、Python の int の最大値を超えない範囲ではこの「信頼できない数値」問題が発生すると考えます。

対策

冒頭に結論を書きましたが、数値としてそのまま扱うことは今のところ難しく、MDN にも以下のような記載があります。

可能な回避策として、代わりに String を使用してください。

大きい数値は BigInt 型を用いて表すことができます。

文字列として扱うというのは「あるある」だと思いますが、Visualization で使う際にはどこかで数値にキャストされているようで、誤差のある状態の数値となってしまいます。

ある程度は誤差を許容して使うか、金額であれば千円や百万円単位にするなど、桁数をクエリ側で調整するなどの工夫も考えられます。

f:id:ariarijp:20201124231242p:plain

BigInt については、どうやら期待を満たしてくれそうではありますが、これは Redash 単体だけでは解決しない可能性が高く、すぐに解決するようなことではないと思いました。

f:id:ariarijp:20201124231554p:plain

まとめ

ふと目にしたツイートきっかけで、意外な事実を知ることができました。

Redash は 17桁を超えるような数値を扱うような環境でも使われている(?)ということに、Redash ファンとして嬉しさも感じつつ、調査を進められた気がします。

私は趣味で Redash エゴサをしていますが、なにか質問などあれば、ぜひフォーラムへ投稿をおねがいします。

Redash のフォーラムには日本語チャンネル(英語以外の言語チャンネルは日本語だけ!)があるので、日本語で質問できますし、私も知っている限りの範囲になりますが、フォーラムで質問に回答しています。

discuss.redash.io

Happy Querying!

いまさら Redash の マルチバイト検索対応について調べてみた

f:id:ariarijp:20200831234000p:plain

設定画面にある Feature Flags > Enable multi-byte。

日本のユーザーならオンにしていることが多いと思いますが、この設定をオンにすると内部的には何が起きるのか。

v9.0.0-beta ブランチで確認した結果、答えは「PostgreSQL全文検索の仕組みを使わず、キーワードがクエリ名または説明文に含まれるかを ILIKE で部分一致検索する」でした。

github.com

日本語で全文検索と言えば PGroonga が思いついたのでドキュメントを眺めてみると、PostgreSQL全文検索は英数字のみサポートしていると書いてありました。

Redash が内部的に利用している SQLAlchemy-Searchable が CJK をサポートしていないのかと思っていたのですが、どうやら PostgreSQL全文検索の制約のようです。

PGroonga は Docker イメージも公開されているので、Redash に組み込めるか検証したくなってきました。

メッシュ WiFi の導入後 Nature Remo の WiFi 再設定がうまくいかなかったときにやったこと

COVID-19 の影響でリモートワーク生活が続いていますが、居室と仕事部屋が対角線上の位置にあり、ときおり ZOOM などが不安定になってしまうので、以前から気になっていたメッシュ WiFi を導入しました。

期待する結果(少なくとも電波強度は明らかに改善しました)がでるかは明日以降の仕事でわかるのですが、そのまえに自宅のネットワーク環境をすべて切り替えるのにひと苦労あったという話です。

ちなみに、これまでは TP-Link の C3150 を使っていたので、メッシュ WiFi の構築に使った機器は TP-Link の deco シリーズ(m9 plus + m5)にしました。

自宅の回線が NURO なので、二重ルーターを避けるためブリッジモードで使っているのがやや残念です。

Nature Remo の WiFi 再接続がうまくいかない問題

難なく m9 plus と m5 でメッシュ WiFi を構成し、既存の C3150 を撤去した後に、いくつかの機器の設定を切り替え忘れていることに気づきました。

そのなかのひとつが、我が家ではテレビの電源操作などで重宝している Nature Remo でした。

設定し忘れたことに気づき、Nature Remo の Android アプリを開いてみたところ、以下のような再設定手順があったので、それに従って設定を進めました。

Q6-3. Nature RemoのWi-Fi情報を変更したい — Nature

しかし、接続先のアクセスポイントを指定しても、設定に失敗したとエラーがでてしまい、何度リセットボタンを教えても変わらず、先に進めない状態になりました。

念のため、アプリ上から既存のデバイス設定を削除し、新規デバイスとして再設定してみようとするも、結果は同じく失敗が続きます。

設置場所の電波環境も問題なく、ただ接続は失敗するという状況で気持ちが折れかけ、当面は Remo を諦めるかとも思ったのですが、ふと思い立った以下の対応でつながるようになりました。

  • メッシュ WiFi の中継側機器の電源を切る(WAN側の機器のみにする)
  • メッシュ WiFi の帯域を 2.4MHz のみ に設定する
  • メッシュ WiFi の WAN 側機器を再起動する

切り分けをしたわけではなく適当にやったので、実際どれかひとつの手順でよかったのか、あるいは全く他の問題が偶然おきていて、それによって設定ができなかったのかはわかりませんが、なんにしても私の場合はこの対応で解決できました。

再設定完了後は、中継機側を追加しても、5GHz を有効にしても、今のところ特に困らず利用できています。

既存の設定を削除してしまったことで、エアコンの設定などもすべて消えてしまったのですが、それによって導入以来 IFTTT 連携で使っていた設定をすべて削除し、Google アシスタントのみで動かせるように移行ができたのでよしとします。体感で2秒ぐらい、赤外線が飛ぶまでのラグが減った気がします。

珍しく Redash が一切でてこない記事になりました。

Redash が活きると思うところ、活かせないかもしれないところ

近々 Redash について話す機会があるのだけど、これから Redash を使ってみようと思う方に「どういう課題があったら試してみてほしいか」あるいは「こういうところでは Redash の良さが活きないかも」というのを考えているので、メモついでに公開。

念のため書いておきますが、これらはひとりの Redash ユーザー個人としての意見であり、また、Redash が公式に発表していることではありません。

Redash が活きると思うところ

  • データをチーム、組織、会社全体で共有したいが、コストは最小化したい
    • Redash は Self-hosted でも SaaS 版でもユーザー数無制限です
  • 扱いたいデータソースの種類が多い
  • データ抽出を毎回エンジニアへ依頼している
    • Redash によって解決された問題として一番わかりやすい例です
  • 社内にエンジニア組織があり、OSS プロダクトへの理解がある
    • とりあえず試してみる、わからなかったら調べる、どうしても変えたいところは自分で直すという気持ちがあると良いと思います
  • データ活用の文化を浸透させたい
    • Redash 利用をきっかけに社内で SQL やデータベースについての理解を深めるような取り組みをされているような企業も多いようです

Redash が活かせないかもしれないところ

  • 分析可能な形で蓄積されたデータがない
    • データ基盤がないと Redash は活躍しにくいかもしれません
    • 個人の印象ですが、BigQuery や Athena にデータを蓄積し、Redash からクエリーを実行するという事例が多いような気がします
  • 特に共有などは不要で、ひとりでデータを見られれば良い
    • デスクトップでサクサク動くTableau Desktop や Power BI などのツールから始めるのがよいかもしれません
      • これらのツールが「共有」をおろそかにしているという意味ではないです
  • コストを全くかけずに利用したい
    • Self-hosted でもインフラのコストは必要なので、必要なものにはコストをかけるということに理解が必要かもしれません
  • クエリーを絶対に書きたくない
    • 書かなくていいツールを探してみましょう。OSS では Metabase なども最近利用されている印象です
  • ダッシュボードやグラフに高い表現力を求めている
    • Redash のダッシュボードやグラフは必要十分なものではあると思いますが、言い方を変えると「素朴」なものでもあります
  • 日本語で手厚いサポートがほしい
    • 私の知る限りでは Redash の日本法人や代理店は無いので、やりとりは基本的に英語になります
    • 何か知りたいことがあれば、ドキュメントやソースコードを読むか、フォーラムで質問することになりますが、フォーラムで質問したら必ず回答が得られるわけでもないのでご注意ください

動画ファイルのコンタクトシートを vcsi を使ってコマンド一発で出力する

GitHub で Star/Fork したリポジトリを見直してて、便利だった記憶があるので個人的なメモ書き。

github.com

仕事柄動画ファイルに触れることが多いので、その時に調べたような気がする。

ちゃんと中身見てないけど、Pythonffmpeg をラップした感じのものだと思う。

使い方は以下。ffmpeg が必要なので vsci の README とかを参考によきように。パッケージマネージャは最近 Poetry 使うようにしている。

$ poetry init -n
$ poetry add vcsi
$ poetry run vcsi vsci.mov -t -w 850 -g 10x10
Processing vcsi.mov...
Sampling... 100/100
Composing contact sheet...
Cleaning up temporary files...

すると、10x10 のコンタクトシートを作ってくれる。

f:id:ariarijp:20200109140717j:plain

また何かの機会に使うことがあるかもしれない。

(余談として、サンプルが小さくてわかりにくいけど、手頃な動画がなかったので手元のターミナルで懐かしの sl コマンドを実行したものを動画キャプチャした)