patorashのブログ

方向性はまだない

2017年を振り返ってみる

今年ももうすぐ終わるので、色々と振り返りをしてみようと思います。

仕事面

仕事は、

  • 営業の方とかサポートの方とはRedMineで課題を管理
  • 普段は基本的にChatworkで意見交換
  • 定例会でお客さんからのフィードバックをもらい、RedMineにチケットを書いて優先順位を決める

というやり方がずいぶん浸透してきたなというところです。どこもそうなのかもと思いますが、課題をすぐにExcelで管理したがるので、RedMineを使いましょうというのを口酸っぱくChatworkにも書いていたと思います(Chatworkに書かれた内容をRedMineのチケットに私が転記したりもした)。

私の担当しているサービスももう4年になるので、規模もそこそこ大きくなり、新しい技術を導入しづらくなったので流行している技術を試すのが難しくなっています。まぁこれは別に悪いことではないのですが、流行のキャッチアップができていないんじゃないかという焦燥感を感じることはあります。かといって、改善点がなくなったということはなく、日々サービスの改善に努めています。

主に今年やったことは、

とまぁ、書ける範囲だとこのくらいでしょうか。 特に、Elasticsearchのバージョンアップはずっと心に引っかかっていたのをようやくアップグレードできたので、終わったときはかなり嬉しかったです。

個人面

体重が圧倒的成長をしているので、そろそろ減量しないとなぁ…とは思っています。

そういえば、ももっこカード検索というWebサービスを作ってリリースしていました。岡山県のももっこカードという子育て家庭応援カードで、協賛店で掲示すると割引などのサービスが受けられるのですが、そのお店がどこにあるのかなかなかわからないので、自分のいるところから近いお店を探せたらいいなということで作っていたのでした。でも自分でも最近全く利用してないです。ただ、お店によってはすごく割引受けられるので、おすすめです。

新たな技術の習得として、Dartをやろうとしているのですが、まだまだ中途半端なので、Dartで何かアプリなり作ることを目標にしていきたいと思います。

すぐに興味が移ってしまい、成す前にやめてしまうことが多いので、個人的にもちゃんとタスク管理を行っていきたいなと思います。

来年やりたいこと

仕事

  • マテビューを効果的に使って高速化する
  • キャッシュの活用法に詳しくなる
  • 社内向けにREST APIを整備する
  • プレゼンしたアイデアのプロトタイプを作る

個人

  • DartWebサービスを作る
  • postgresqlの資格を取る
  • 自分に何かあったとき用のドキュメント作成
  • 家のデスク周りの整備
  • ウッドデッキが欲しい
  • 英語の本を苦労なく読めるくらいになる

DartでFullscreen APIを実行する

Darthtml5のFullscreen APIを実行したいと思ったのですが、メソッドがあるにも関わらず、どうにも動きませんでした。

import 'dart:html' as dom;

main() {
  var canvas = dom.querySelector('#canvas--fullscreen');
  canvas.requestFullscreen(); // 動かない!
}

ベンダープレフィックスが必要

html5のFullscreen APIは、まだベンダープレフィックス(webkitとかmsとか)が必要な状態で、JavaScriptであっても単純には呼べないようです。JavaScriptだと、webkitRequestFullscreenとかのメソッドがあるのですが、Dartdart:htmlパッケージには1つしかありません(requestFullscreenのみ)。

DartからJavaScriptのメソッドを呼び出す

リフレクションのような形になりますが、dart:jsパッケージを使って、ElementJsObjectに変換し、callMethodメソッドを使ってベンダープレフィックスのついているメソッドを呼び出すようです。

import 'dart:html' as dom;
import 'dart:js';

/// フルスクリーンで表示します。
/// 
/// [element]のFullscreen APIを呼び出します。
/// [参考URL](https://stackoverflow.com/questions/29714889/how-to-request-fullscreen-in-compiled-dart)
void fullscreenWorkaround(dom.Element element) {
  var elem = new JsObject.fromBrowserObject(element);
  if (elem.hasProperty("requestFullscreen")) {
    elem.callMethod("requestFullscreen");
  } else {
    List<String> vendors = ['moz', 'webkit', 'ms', 'o'];
    for (String vendor in vendors) {
      String vendorFullscreen = "${vendor}RequestFullscreen";
      if (vendor == 'moz') {
        vendorFullscreen = "${vendor}RequestFullScreen";
      }
      if (elem.hasProperty(vendorFullscreen)) {
        elem.callMethod(vendorFullscreen);
        return;
      }
    }
  }
}

main() {
  var canvas = dom.querySelector('#canvas--fullscreen');
  fullscreenWorkaround(canvas); // 動く!
}

このあたりの処理もrequestFullscreenメソッドに実装してくれて透過的に扱えたらいいのになぁと思いました。

List.forEachでasync, awaitしたいならFuture.forEachを使おう

これはDart Advent Calendar 2017の15日目の投稿です。

qiita.com

カレンダーがガラガラで寂しかったので、メモ書きですが、参加しました。

今コツコツとDartでちょっとしたゲームアプリを作ろうとしているのですが、1秒ごとに処理を行いたいと考えていました。もちろんDartなので非同期で。

1秒ごとに処理がされない

最初はこれでいけるんじゃないか?と思って書いてみました。

main() {
  List<Foo> foos = []
  for(int i = 0; i < 20; i++) {
    Foo foo = new Foo();
    // なんやかんやで…
    foos.add(foo);
  }

  foos.forEach((foo) async {
    await new Future.delayed(new Duration(seconds: 1));
    foo.bar();
  });
}

こうすると、1秒ごとに20秒まで処理が行われ…ずに、1秒後に20個分の処理結果がドンと表示されました。 よくよく見ると、たしかにそうなるわなぁ…と思います。

これで1秒ごとに処理できる!

for inを使えばできるが…

for inを使えば、処理はできましたが、forはなんかダサイ…。しかもその処理の関数にasyncつけないといけなくなるのでいただけない。

main() async { // 上の関数にasyncつけないといけない
  // foosを作る処理は省略
  for(foo in foos) {
    await new Future.delayed(new Duration(seconds: 1));
    foo.bar();
  }
}

Future.forEachを使おう

これが一番綺麗でわかりやすいです。イテレータが渡される関数にasyncをつけるだけでよいので見た目もいいですね。

main() { // 上の関数にasync必要なし!
  // foosを作る処理は省略
  Future.forEach(foos, (foo) async { // こちらにasyncをつける。
    await new Future.delayed(new Duration(seconds: 1));
    foo.bar();
  });
}
参考リンク

api.dartlang.org

投資で大損した時に学んだこと

これは投資・資産運用 Advent Calendar 2017の9日目の投稿です。

adventar.org

私が投資家デビューしたのはFXだったのですが、実は一度退場に追い込まれたことがありまして…。それが、リーマンショックでした。 なんでFXにしたのか?とかは別の機会で書くことにします。

なぜリーマンショックで退場せざるをえなかったのか?

リーマンショックってなに?っていうのはググってください。ざっくり言うと大手のリーマン・ブラザーズが破綻したことによる衝撃で資産を守るために様々な金融商品が売られて世界中で大暴落を引き起こしたって感じです。

まぁロスカット(強制決済)になってしまったからなのですが、どうして強制決済になったかというと、レバレッジをかけ過ぎていたからです。

レバレッジとはなんぞや?

レバレッジとは、いわゆるテコの原理というやつで、持っているお金以上の金融商品に投資することができるものと考えてください。株の世界では「信用取引」というものがありまして、これもレバレッジの効いた取引です。

500円持っていて、500円以下の買い物をする場合はレバレッジのない状態です。 500円持っていて、それを担保に1500円を借りたとしたら、レバレッジ3倍の状態です。

レバレッジのないパターン(得する編)

たとえ話をします。

100円のお菓子があります。 私は500円持っています。これを売って儲けたいと考え、5つ買いました。 すると、このお菓子が品薄になり、130円で売られるようになったので、130円で売りました。 130円で売れたので、130x5=650円となり、150円儲かりました。

うん、普通ですね。

レバレッジのあるパターン(得する編)

たとえ話をします。

100円のお菓子があります。 私は500円持っています。これを売って儲けたいと考えました。 「このお菓子は絶対に人気が出るだろうから、500円を担保にお金を借りよう」 そして、1500円を借り、15個買いました。(レバレッジ3倍) すると、このお菓子が品薄になり、130円で売られるようになったので、130円で売りました。 130円で売れたので、130x15=1950円となりました。 ここで借りていた1500円を返しましたので、担保にしていた500円は戻ってきました。 手元には、もともとの500円と、1950円 - 1500円 = 450円を併せた950円が残りました。

同じ500円という元手なのに、レバレッジがない場合は150円しか儲からず、 レバレッジのある方は450円も儲かりました。

ウハウハです。

レバレッジのないパターン(損する編)

たとえ話をします。

100円のお菓子があります。 私は500円持っています。これを売って儲けたいと考え、5つ買いました。 しかし、このお菓子が大量生産され、じわじわと値下がりし、70円で安売りされるようになりました。 値上がりしそうもないので仕方なく70円で売ってしまいました。 70 x 5 = 350円になりました。

150円損はしましたが、手元には350円残っています。

うーん、まぁ、普通です…。損したけど。

レバレッジのあるパターン(損する編)

たとえ話をします。

100円のお菓子があります。 私は500円持っています。これを売って儲けたいと考えました。 「このお菓子は絶対に人気が出るだろうから、500円を担保にお金を借りよう」 そして、1500円を借り、15個買いました。(レバレッジ3倍) しかし、このお菓子が大量生産され、じわじわと値下がりし、70円で安売りされるようになりました。 500円を担保に1500円を貸してくれた人は、「これ以上損はできない!」と強制的に70円でお菓子を売り、担保の500円も回収しました。 手元には、何もありません。0円になりました。

悲しくて涙が出てきます。

レバレッジのないパターン(もっと損する編)

たとえ話をします。

100円のお菓子があります。 私は500円持っています。これを売って儲けたいと考え、5つ買いました。 しかし、このお菓子が全く人気が出ず、突然20円で安売りされるようになりました。突然です! 仕方なく20円で売ってしまいました。 20 x 5 = 100円になりました…。

400円損はしましたが、手元には100円残っています。

苦しいけれど、うん、まぁ…。

レバレッジのあるパターン(もっと損する編)

たとえ話をします。

100円のお菓子があります。 私は500円持っています。これを売って儲けたいと考えました。 「このお菓子は絶対に人気が出るだろうから、500円を担保にお金を借りよう」 そして、1500円を借り、15個買いました。(レバレッジ3倍) しかし、このお菓子が全く人気が出ず、突然20円で安売りされるようになりました。突然です! 500円を担保に1500円を貸してくれた人は、「これ以上損はできない!」と強制的に20円でお菓子を売り、担保の500円も回収、さらに損した分700円を要求してきました(いわゆる追証)。 手元には、借金700円が残りました。

こうなるともう吐き気が止まりません。

レバレッジ、ヤバい(両方の意味で)

うまく使うと、めっちゃ儲かるし、下手をすると借金まで抱えてしまうことになるのが、レバレッジです。

FXは基本的にレバレッジを使って儲けようという商品です。まぁレバレッジ使わないとただの外貨預金みたいなもんですからね。

当時、世界の景気はよくて(日本以外は)、すごく高金利でした。私もたまたまFXの情報を見つけて、豪ドル/円でとりあえず始めてみたら、1ヶ月で20万円が30万円になったのでもうやるしかないと思って本格的に取り組み始めたのです。

スワップがすごい

スワップっていうのは利子と思ってください。豪ドルの利子が年6%くらいだったかな…。あんまり覚えてないんですが、それくらい。日本はゼロ金利ですよね。差分の金利がもらえる金利です。つまり、ほぼ6%です。当時、豪ドル円を100万円分買っていると、1年で100万円が106万円になるんです。すごい。

スワップxレバレッジの甘美な果実

ちなみにスワップにもレバレッジかかります。つまり、レバレッジ3倍かけると金利が18%になります。強制決済されなければ、年利18%ですよ。放っておいても儲かるんですよ。1年で100万が118万になるんです。すごいですね。もし値下がりしても金利が損を補填してくれます。これはもう負ける気がしませんね!!そう、強制決済がされなければね!!

強制決済のライン

レバレッジ3倍ということは、三分の二に値下がりしたら強制決済されると考えてください。当時はレバレッジ規制もほぼなくて、レバレッジ400倍とか狂ったこともできたのですが、私はビビりだったのでレバレッジ3〜5倍でやってました。というのも、「レバレッジ3倍くらいならば安全圏でロスカットされるようなことはない」と本で読んでたからです。この頃はドル円は120円前後で、FXの本を読むと「ドル円が100円を切ることはない。切ったとしたらそれは異常事態ですよハハハ」みたいな論調でした。まぁ100円どころか78円まで行くんですけど。

学んだこと

リスクコントロール、大事!ものすごく、大事!!!

  • レバレッジを上げすぎるな
  • 金利通貨は信用するな
  • 勝負するんならストップロス入れろ
  • やっぱりドル円がいい

レバレッジをかけたら安全圏はない

少なくとも、3倍は安全圏ではないです。特に高金利通貨だと。ドル円ならレバレッジ2倍なら安全圏だと思うけれど(保証はしません)。

金利通貨、金利以上に暴落する

損失を補填どころかどんどん損失を出します。スワップなんて焼け石に水だったんや…。(今もトルコリラに苦しんでいる)

金利通貨、暴落するとスワップも減る!

どういうこと?と思うかもしれませんが、金利が変わらなくても資産価値が減ったらスワップは減るんです。金利が6%だったとして、100万円の商品を持っていたら、6万円の利子がつきますね。しかし、その商品が暴落して80万円になったら、80万円x6%=4万8千円しかもらえません。目論見から1万2千円も減るんです。ただでさえ20万円の損をしているのに。レバレッジを効かせていると、減る量も3倍です。つまり、補填が減るので回復しづらくなります。これは滅入る。

レバレッジをかけて勝負するんならストップロス絶対に入れろ

出た利益分を使って勝負をかける時があるんですが、最低でもその利益分以上の損失が出ないように勝負しています。例えば、2万円儲かったので、次はその2万円を元手にして損失が2万円に収まるようにしてレバレッジをかけて勝負する、とかです。

やっぱりドル円

ドル、ほとんどスワップつかないけれど、為替差益をメインに取引したほうがスワップ狙いより安全だと思います。高金利通貨は、スワップがあるから、逃げ出すのを躊躇してしまうという弱点があるし、両建てがしづらいです(両建ては売りと買いを共存させる手法)。高金利通貨を売ると、味方になってたスワップが今度は逆に敵になるんですが、すごく高いので、買いと売りで同じ量持つと日々消耗していくことになるからです。ドル円だと、マイナススワップ大したことないから、両建てもそれなりに気軽に行えます。 殺人通貨と名高いポンドも好きですが、まぁあれ本当にヤバいので…。

まとめ

いかにして勝つかより、いかにして負けずに戦い続けるか、というのが大事だと思います。一度退場すると、戻ってくるのにはかなりの時間がかかります。未だに前に損失した以上の利益は出せていませんし、現在も相当の含み損を抱えていたりしていますが、レバレッジを低く設定して、生き残るほうを選んでいます。下落が続く高金利通貨も、強制決済さえされなければ、いつかは逆転するかもしれません。

生き残りましょう!

ロボアドバイザーを試してみた結果報告

これは投資・資産運用Advent Calendar 2017の3日目の投稿です。

adventar.org

昨日は@NkznTHEOめっちゃ楽だった話でした。THEOもロボアドバイザーで運用みたいですね。

さて、私はというと、投資は色々やっているのですが、ここ最近は株でいえばCookpad株の暴落やFXでいえばトルコリラの暴落で非常に苦しんでいます…。 そんな自分の投資対象の中でも堅調なのが、投資信託とロボアドバイザーです。今回はロボアドバイザーについて書いていこうと思います。

ロボアドバイザーとは?

ロボアドバイザーとは、早い話が投資用のAIが資産運用を代行してくれるという代物です。ある程度まとまったお金は必要になりますが最近は少額から始められるようになっており、しかもそれをちょうどいい塩梅に分散投資してくれます。その代わりに、自分で投資信託を買うよりも少しだけ多めに手数料を取る、という感じです。

ロボアドバイザーのメリット

ロボアドバイザーのメリットは、なんといっても運用の手間から解放されるにも関わらず、パフォーマンスがそこそこいいところでしょう。

ロボアドバイザーというだけあって、いくつかの質問に答えると自分にとって最適な運用プランを提案してくれます。リスクを取って積極運用してもいいのか、リスクを取らずに安定運用したほうがいいのかは、その人の性格や、人生のステージに左右されます。老後に積極運用した結果、資産を減らしたりするのは危険だったりするので。とはいえ、あくまでもアドバイスであり、本人がそのプランを望まないのであれば、質問に答え直してプラン変更をしたりもできます。

ロボアドバイザーのデメリット

デメリットは多少手数料が高い、という点です。確かに、手数料が割安な投資信託を自分で選んで投資するよりは高くなります。それは長期運用をすればするほど顕著になってくると思います。なんせ、ロボアドバイザーの手数料+ロボアドバイザーの買う投資信託の手数料がかかってくるからです。

どこのロボアドバイザーを選んだのか?

実質選んでないのですが、私が楽天証券を使っているので、楽天証券の楽ラップを使ってみました。

wrap.rakuten-sec.co.jp

楽ラップは10万円から始めることができるので、とりあえず私も10万円で運用してみています。なお、楽ラップは手数料が固定報酬制成果報酬制があり、私は固定報酬制を取っています。

運用プランは「やや積極型」

私の場合は質問に答えていったところ、「やや積極型」になりました。投資対象のメインは日本株・外国株・外国債券(9割。3割ずつくらい)で、国内債券やREITが少々(1割。5%ずつ)という感じです。

今年のパフォーマンス

2016年の6月から始めて、すぐに11万になったので年末に1万円解約していたので、2017年1月時点で10万円からのスタートでした。この記事を書いている11月末現在、評価損益は108,496円となり、約8.5%のパフォーマンスとなりました。今年は株高だったので、なかなかよい結果だと思います。

投資信託とのパフォーマンス比較

今年に限って言えば、私が使っている国内株式のインデックス型投信や、外国株式の投信のパフォーマンスは10〜15%くらいだったので、それらに比べるとパフォーマンスは低いですが、それはおそらく「やや積極型」の運用にしたことで、外国債券が3割を占めていたことが原因かなと思います。

まとめ

今後利用するか否か?

自分で分散投資ができるのであれば、別にロボアドバイザーを使わなくてもいいかなー?と思います。自分で言えば、あとは外国債券の投資信託を加えれば同じようなポートフォリオで運用できますし、その分、ロボアドバイザーへの手数料はかからなくなるので、そっちのほうがいいかなと思います。なので、どこかのタイミングで解約するかもしれませんが、もう少し様子見します。

ロボアドバイザーが向いている人は?

どういうポートフォリオを組んだらいいのかわからない人は、まずロボアドバイザーを試してみるのがおすすめかなと思います。投資を始めるときに、初心者が一番困るのは、「何に投資するか」だと思います。とはいえ、自分で投資対象とその比率を考えるのは、最初は難しいです。ロボに任せると適切な投資配分を考えてくれますし、少額であっても分散投資ができます。投資はしてみたいけれど、どうしたらいいのかわからないし、考えたくもない!という人は、ロボに全部放り投げるのがいいと思います。楽ラップなら月々積立で投資できるので、おすすめですよ!

DartのサーバサイドフレームワークのAqueductの紹介

この記事はDart Advent Calendar 2017の2日目の記事です。

qiita.com

Dartは個人的に数年前からDart本を読んでやってみようと思って頓挫、を繰り返していました。

ただ、2016年にGoogleAdwordsAdsenseDartを使っているという記事を読んだり、Sassの実装をRubyからDartにするという記事を見かけてから、Dartはやっぱりいい言語なんじゃないか?と思うようになりました。今年から本腰を入れてやってみようと思ってこのブログにもいろいろと記事を書いていってます。とはいえ、まだアプリは作っていません…。

Dartのよいところは、

  1. 非同期プログラミングに特化
  2. 基本的にはシンプル
  3. サーバサイドもクライアントサイドもいける

という点だと思います。クライアントサイドはAngularDart以外はほぼ選択の余地がありませんが、Googleチュートリアルからドキュメントもしっかりと作ってくれているので、迷うことは少ないかと思います(英語ですが)。

ところが、サーバサイドとなると、デファクトスタンダードがありません。Dartでサーバサイドの実装というのはあまりイメージしないのかもしれません…。しかし、Dartは非同期処理に優れているし、実行速度も速く、静的型付にも動的型付にも対応しています(正確にはDynamic型ですが)。いいフレームワークがあれば、Dartでサーバサイドが流行るのではないか?と考えるようになりました。

今回はDartのサーバサイドフレームワークのAqueductの紹介をしようと思います。

Aqueductとは?

f:id:patorash:20171202002538p:plain

Aqueductは、英語で「水路」とか「水門」を意味するようです。Aqueductのアイコンは、水門とAの形を合わせたようなデザインになっています。

aqueduct.io

AqueductはDart Summit 2016で取り上げられており、Dart界隈では有名なサーバサイドフレームワークなのだと思います。開発はstable kernelという会社が行っているみたいですが、オープンソースでバージョンも現在2.5と、開発も継続しています。

github.com

また、ドキュメントもあり、チュートリアルがあって、それをやっていくとAqueductの強力さがわかるかと思います(ただし英語です)。

特徴

Aqueductの特徴は、

  1. 最初からマルチスレッドで起動する設定になっている
  2. ルーティング設定がシンプル
  3. ORMをフレームワークが持っている
  4. DBのマイグレーション機能をフレームワークが持っている
  5. OAuth認証機能を最初から実装している
  6. ControllerのActionで受け取るパラメータをアノテーションを使って型のある状態で受け取れる
  7. 最初からテストができる状態になっている(TDDができる)

というところです。ただ、最初はAPIサーバに特化したような状態になっています。もちろん、静的なファイルを返すこともできますが、恐らくはAPIサーバとして使うことがメインとして考えられているのだと思います。

チュートリアルをやってみた

先月の上旬にチュートリアルをやってみました。

patorash.hatenablog.com

チュートリアルの内容は、APIサーバを作るのですが、その過程でデータベースを作ってModelファイルを定義してそこからマイグレーションを行ったり、テストを書いていったりと実用的な内容でした。

私は普段、仕事ではRuby on Railsでサーバサイドの実装を行っているのですが、Railsエンジニアが他のフレームワークに手を出してよく思ってしまう「やっぱりRailsのほうがいいんじゃね?」という気持ちが全く湧きませんでした。パラメータの型チェック、型変換などもAnnotationで行った上でActionで受け取れるので、「これいいじゃん!」と思うことのほうが多かったのです。

ですので、Dartでサーバサイドプログラミングに興味のある方は、是非Aqueductをやってみるといいと思います!私もこれから頑張ってみようと思います。

なぜDartをやっていくと決意したか

実は数年前に、Kotlinをやり始めた頃がありました。今は全くやっていないのですが、当時私はAndroidアプリを作ったりしていて、Kotlinを知ったときにすごく衝撃を受けて勉強会でKotlinのことを話したりしていました。ですが、周りの反応はまぁ大体、「Javaでよい」、「それScalaでできるよ」、「中途半端でどうせ流行らない」というものでした。私はもともとJavaがあんまり得意でもなかったので、周囲からそういう意見をバンバン言われるたびに本当に傷つき、業務でもAndroidアプリ開発はやらないのでKotlinも段々やらなくなってしまいました。

ところがどうでしょう?今はもうKotlinがAndroid開発のメイン言語と言っても過言ではありません。内心「だからKotlinいいよってあんなに言ってたじゃねーか!」と思いつつも、全然書いてないのでもう書けないし、やっぱり人の意見とか適当に受け流してやっていくのがいいなと確信しました。

Dartも、Dart本を一通り読んで、やってみて、「まぁライブラリはそこまで整ってないけれどいい言語だ」と思っています。Dartいいっすよという話をすると大体周囲は「Dartってもうオワコンでしょ?」という反応です。ですが、モバイルアプリフレームワークのFlutterの登場など、むしろDartはこれからじゃないかなと思っています。

DartJavaとLLのいいとこ取りのような言語だと思います。型を意識せずにDynamic型でガンガン実装できるのでプロトタイピングもしやすいと思いますし、後々、型をつけていくということができるので、堅牢なプログラムにすることが可能です。そしてDartVMが速い。

何が何でもDartをやっていくという決意表明で、この記事を終わります。

SearchBoxのmax_result_windowは変更できない

私が関わっている製品で、HerokuのElasticsearchのアドオンはSearchBox(Searchly)を使っているのですが、これでハマったのでちょっと調査した結果を残しておきます。

検索結果画面のページ移動のところで、ページ番号の大きなページにアクセスしようとすると、500エラーが発生していました。メッセージは以下のような感じです。

Result window is too large, from + size must be less than or equal to: [10000] but was [80000]. See the scroll api for a more efficient way to request large data sets. This limit can be set by changing the [index.max_result_window] index level parameter

from + sizeが10,000以上だから大きすぎる。scroll apiを使うか、index.max_result_windowの値を大きくしてくれということです。ページング処理自体はkaminari gemに任せていたのですが、件数が多すぎたらこんなことになるとは…。ちなみにこの制限はElasticsearch2から加わったそうです。max_result_windowが大きいと、その分多くのメモリを使ってデータを確保した後に絞込みを行なうことになるので、やたらと大きな数値であることはよくないようです。

とはいえ、変えるだけで済むなら…と思い調べたところ、max_result_windowを設定する方法はすぐに見つかりました。

ElasticSearch - Result window is too large, from + size must be less than or equal to: [10000] · GitHub

これをローカルで変更してみたところ、直りました。

curl -XPUT http://localhost:9200/index_name/_settings -d '{ "index" : { "max_result_window" : 1000000 } }'

SearchBoxのほうでも変えようとしたのですが、設定画面がありません。同じ様にcurlAPIにアクセスしてみたのですが、バリデーションエラーで弾かれました。公式ドキュメントを見た所、settings APIは公開していない模様です。

devcenter.heroku.com

elasticsearch-modelを使っているので、create_index!をするタイミングでなら設定できるかもしれないと思い、やってみました。 その後、以下のように設定を取得してみました。

curl -XGET http://localhost:9200/index_name/_settings

ローカルでは、max_result_windowが書き換えることができました。

{"index_name":{"setting":{"index":{"max_result_window":1000000,...}}}}

これをSearchBoxに対して実行したら、max_result_window自体がありませんでした。

{"index_name":{"setting":{"index":{...}}}}

ローカルでは成功しましたが、やはりSearchBoxではダメでした。

対処法

対処方法としては、以下の2つが考えられます。

  1. 上位1万件までを表示対象にする
  2. 別のアドオンを使う(bonsaiなど)

2の方法は、teratailの質問でそういう回答があったので、おそらくbonsaiだとmax_result_windowの値が変更できるのだと思いますが、検証はしていません。

teratail.com

今回は1の方法で対応するようしました。

まとめ

Elasticsearchはランダムページアクセスに弱いようです。 search_afterを使えば、1万を超えたアクセスはできるようですが、ページング向きではありません。search_afterは、ステートレスなscroll apiのような動きのようです。

www.elastic.co

とはいえ、ちゃんと絞込みすればいいだけの話なので、そちらに合わせる様にしたほうがよさそうだなと思います。