ユーザに対して「自分の行きたそうな記録」を見せたい(1)

今のヤマレコは検索の機能が貧弱で、キーワードの検索やデータベースの各項目の検索しかできません。今後の機能追加として、自分に合った記録を適切に提示してくれるような機能が欲しいと思って色々検討してます。

結果的にシステムから見ると、記録の検索機能になるので

  • 検索するときに何をInputするか
  • どの記録をどういう順番に並べて表示するか

の2点を考える必要があります。

検索するときに何をInputするか

ユーザがラクをするには、明示的に示さないような仕組みが要ります。例えば、過去の記録の傾向とか、プロフィールとか。
でも、過去の記録のうち、どの記録を中心にするのか、とか、ユーザがプロフィールを正確に入れてくれていない場合もある、とか、ラクをする代わりに精度が下がってしまう問題があります。

そこで、少し面倒になりますが、探したい記録に関する情報を少しはユーザ側が提示する前提で考えます。まずは、自分の行った記録を選んで、この記録に近い記録を探す、みたいな機能ができればいいかなぁと。

どの記録をどういう順番に並べて表示するか

ある記録に近い記録(この記録を書いたなら、この記録は近いはず、みたいな)を提示するには、記録と記録の関係を調べて、1次元のリストに並べる必要があります。

その一方で、パラメータは

  • 季節
  • 日数
  • ジャンル
  • 歩いた時間(コースタイム)
  • 歩いた距離
  • 高度差
  • 最高点の標高
  • エリア
  • パーティのメンバー数
  • 利用した装備

などなど、挙げだしたらキリがないです。どこから検索されるかもわからない状態で、何次元もあるパラメータの中から何をどう優先的に表示させるのか、まともに考えるとできそうな気がしません。

仕方がないので、まずはパラメータを絞り込んで2次元で作って、どのぐらい精度が高いのかを見てみることにしました。今回は

  • 歩いた距離
  • 高度差

の2次元のグラフ上で記録を整理して、記録間の近さを座標上の距離で判断しようと考えました。

課題1:高度差の取り方

高度差と言っても、高度差の取り方にもいろいろあります。最高点と最低点の高度差を取ると、縦走している場合とピークハントの差がでないのである程度デコボコしていることも分かるように高度差を取ります。

細かく取ろうとして、GPSログの各座標ごとに登りと下りの加算をしていく方法を採用すると、細かい登りと下りも加算されてしまい、GPSログの採取ポイント数が多いと高度差が大きくて、採取ポイント数が少ないと高度差が小さいという結果になってしまいます。

そこで、上記の2つの間を取るようにしました。例えば高度差が100m以上着いたときだけ、加算するようにするとGPSのポイント数にも左右されにくく、ある程度デコボコしていることも表現できるはずです。

また、登りと下りの片方が長い場合は、標高差が大きい方を取ることにしました。

課題2:近い記録を見つけるときの性能

各記録を距離と高度差の2次元座標軸にちりばめた時、例えばある記録A(もしくは、座標上のある特定の点)から近い記録を正確に探そうとすると、その記録A以外の数万もの記録について、記録Aとの距離を計算して、近いものを表示することになります。

しかし、検索をするときはブラウザのボタンをクリックしてから表示するまでのせいぜい数秒、実際はネットワークの遅延やブラウザの処理時間もあるので数100ms程度の時間で終わらせないと、体感速度としてやってられません。

まともに数万件の記録間の距離を毎回計算していると、どう考えても表示までには間に合いません。夜間のバッチ処理等で毎回記録間の距離を計算してもいいのですが、記録数が多くなってくるとバッチ処理の負荷も馬鹿になりません。

今回はその対策として、2次元の空間をある程度ブロック分けして、検索するときは、そのブロックの中にある記録を並べるようなやりかたにしようと思います。

課題3:ブロックの切り方

では、ブロック分けをするとして、どうブロック分けをすればいいのでしょうか。縦軸に標高差、横軸に歩いた距離を取ったとき、標高差が低く距離が短い場所に記録が偏って、泊数が多くなるような距離が長いものは記録が少ないような分布になるはずです。

ブロックを住所のような感じで、あらかじめ縦と横の座標を区切ってしまうと記録の数が増えてくると偏ってる領域のブロック内の記録数が多くなってしまって関連性の高い記録を表示するというもともとの目的が達成できなくなってしまいます。

そこで、例えば、1つのブロックには記録が200件しか入らないように、今回は動的にブロックを分けるようなやり方を採用しました。最初は1つの大きなブロックだけ定義しておいて、ブロック内の記録が200件を超えたら、ブロックを縦横4分割してブロック内に記録を追加して、200件を超えたブロックをまた4分割するようなやり方にしました。

検索をどうやるか

2次元空間上のあるブロック分けした中は、ランダムなり何なりで記録を並べて、ブロック内ではいい記録が見当たらなかったときは、その隣のブロックを探していくような並べ方が必要なんですが、どの隣を次に表示するのかが難しいです。ここは検討中。

試作で確認

どの程度正確に表示されるのか、まずは試作で確認してみました。

  • 今のヤマレコの記録を2次元空間にならべて、どういう分布になっているのか
  • ブロック分けをしてみて、同じブロックに入っている記録が近い記録になっているのか

とりあえず2点確認してみました。

確認1:今のヤマレコの記録分布

縦軸に標高差(0〜4000m)、横軸に距離(0〜40km)のグラフを作ってみました。

予想通り、標高と距離が短い記録に偏ってました。

確認2:同一ブロックが近い記録になっているか

結論としては、ダメでした。特に標高差を使って判断しているところが、0mから登って500mに行くハイキングの記録と、2000mから2500mに行くピークハントの記録が同じブロックに配置されていました。

今日の結論

やはり2次元では精度に限界があるので、もう少しパラメータを増やして多次元にしていこうと思います。あまり増やしすぎるとブロック分けが難しくなっていくので、何のパラメータで多次元にするのか、色々検討してみます。

おまけ

考えたことややったことの記録をブログに残すのは重要なんですが、誰向けに残してるのかよくわからない内容になってしまいました。後から自分が見るかというと見ないし、他の人も見てないだろうしなぁ。まぁ、自分の頭の整理に時間を割いたと思えばいいのかな・・・。