Solrで入れ子構造の文書をインデックスする

入れ子構造の文書

入れ子になった文書をそのままインデックスできると便利なことがあります。たとえば

  • 親文書:ブログ本文、子文書:コメント
  • 親文書:製品の基本情報、子文書:サイズ違い、色違いなどのバリエーション
  • 親文書:音楽プレイリスト、子文書:曲

などです。

Solrで入れ子構造を扱う

Solrは入れ子になった文書を扱うことができますが、そのためにはいくつかの条件と制限があります。

  • 親-子の2階層まで
  • indexされるがstoreされない root フィールドを持つ。同一の文書に含まれるすべての親要素、子要素は自動的に root フィールドに同じ値を与えられる
  • 親階層の文書であることを示すフィールドを持つ。検索時の条件として使う。
  • いわゆるスキーマレスの設定が必要。構造の異なる(場合が多い)親と子を同じコア(コレクション)内で扱う必要があるため

例: プレイリスト

以下のようなプレイリスト情報を Solr に与えます。
(_default の configset で core を作っていればスキーマレスでインデックス作成できます)

{
    "id":"list_1",
    "contentType":"playlist",
    "title":"list1",
    "songs":[
	{
	    "id":"song_1",
	    "contentType":"song",
	    "title":"title1",
	    "artist":"artist1",
	    "trackNum":1
	},
	{
	    "id":"song_2",
	    "contentType":"song",
	    "title":"title2",
	    "artist":"artist2",
	    "trackNum":2
	}
    ]
},
{
    "id":"list_2",
    "contentType":"playlist",
    "title":"list2",
    "songs":[
	{
	    "id":"song_3",
	    "contentType":"song",
	    "title":"title3",
	    "artist":"artist3",
	    "trackNum":1
	},
	{
	    "id":"song_1",
	    "contentType":"song",
	    "title":"title1",
	    "artist":"artist1",
	    "trackNum":2
	}
    ]
}

こういう入れ子構造を検索するのに使える Block Join Query Parser が用意されています。

親文書すべて

q={!parent which="contentType:playlist"}

"response":{"numFound":2,"start":0,"docs":[
      {
        "id":"list_1",
        "contentType":["playlist"],
        "title":["list1"],
        "_version_":1630800916686831616},
      {
        "id":"list_2",
        "contentType":["playlist"],
        "title":["list2"],
        "_version_":1630800916689977344}]
  }

子文書の情報もまとめて取得

ChildDocTransformerを利用します。

q={!parent which="contentType:playlist"}
fl=id, title, [child parentFilter="contentType:playlist" childFilter="contentType:song" fl=id,trackNum,title,artist]

"response":{"numFound":2,"start":0,"docs":[
      {
        "id":"list_1",
        "title":["list1"],
        "_childDocuments_":[
        {
          "id":"song_1",
          "title":["title1"],
          "artist":["artist1"],
          "trackNum":[1]},
        {
          "id":"song_2",
          "title":["title2"],
          "artist":["artist2"],
          "trackNum":[2]}]},
      {
        "id":"list_2",
        "title":["list2"],
        "_childDocuments_":[
        {
          "id":"song_3",
          "title":["title3"],
          "artist":["artist3"],
          "trackNum":[1]},
        {
          "id":"song_1",
          "title":["title1"],
          "artist":["artist1"],
          "trackNum":[2]}]}]
  }

「”title2″を含むプレイリスト」

q={!parent which="contentType:playlist"} title:title2
fl=id, title, [child parentFilter="contentType:playlist" childFilter="contentType:song" fl=id,trackNum,title,artist]

"response":{"numFound":1,"start":0,"docs":[
      {
        "id":"list_1",
        "title":["list1"],
        "_childDocuments_":[
        {
          "id":"song_1",
          "title":["title1"],
          "artist":["artist1"],
          "trackNum":[1]},
        {
          "id":"song_2",
          "title":["title2"],
          "artist":["artist2"],
          "trackNum":[2]}
}

部分的に更新するとどうなるか

更新するときは親子関係にある文書をすべてひとまとめにすること、という制限を破るとどうなるか試してみました。

{
        "id":"list_1",
        "title":["list1"],
        "_childDocuments_":[
        {
          "id":"song_1",
          "title":["title1"],
          "artist":["artist1"],
          "trackNum":[1]},
        {
          "id":"song_2",
          "title":["title2"],
          "artist":["artist2"],
          "trackNum":[2]}]
}

というプレイリストの一部分だけを更新してみます。

{
    "id":"song_2",
    "contentType":"song",
    "title":"title22",
    "artist":"artist2",
    "trackNum":2
}

上のようなデータを与えてupdateしても特にエラーにはなりません。

q=title:title2

{
        "id":"song_2",
        "contentType":["song"],
        "title":["title2"],
        "artist":["artist22"],
        "trackNum":[2],
        "_version_":1630801429121728512}]
}

title:title2 という条件で検索してみると id:song_2 単体として見れば更新されていることが分かりますが、実は親子関係は破壊されてしまってます。

q={!parent which="contentType:playlist"}
fl=id, title, [child parentFilter="contentType:playlist" childFilter="contentType:song" fl=id,trackNum,title,artist]

"response":{"numFound":2,"start":0,"docs":[
      {
        "id":"list_1",
        "title":["list1"],
        "_childDocuments_":[
        {
          "id":"song_1",
          "title":["title1"],
          "artist":["artist1"],
          "trackNum":[1]}]},
      {
        "id":"list_2",
        "title":["list2"],
        "_childDocuments_":[
        {
          "id":"song_3",
          "title":["title3"],
          "artist":["artist3"],
          "trackNum":[1]},
        {
          "id":"song_1",
          "title":["title1"],
          "artist":["artist1"],
          "trackNum":[2]}]}]
}

検索実行時にJOINする方法との比較

この記事でご紹介したのは入れ子構造のままインデックスする方法です。それとは別に、親文書と子文書を別々のコア(コレクション)に分けて検索時にJOINする方法もあり、パフォーマンスと扱いやすさとのトレードオフが存在します。

  • 入れ子のまま扱う: 親子関係の情報自体をインデックスするのでパフォーマンス面で有利だがその分制限強め
  • 検索時JOIN: パフォーマンス面では不利だが柔軟

ランダムな感じでワイワイ配置したデザインの作り方

こんにちは、三年目デザイナーのはなです。

私は洗練されたミニマルでシンプルなデザインも好きですが、どちらかというと装飾をワイワイたくさん置いた華やかなデザインの方が好きです。

今回はそんなワイワイしたデザインを作るときに欠かせない、バランスの良いオブジェクトのランダム配置のやり方についてお話します。

オブジェクトの準備

まず、オブジェクトを大まかに、大・中・小に分けます。

「大」は主役、もしくは準主役です。

真ん中にタイトルなどが来る場合はそれが主役になるので、「大」のオブジェクトは準主役になります。タイトルなどがない場合(イラストなどだけをランダム配置する場合)は主役になります。

基本的には一つの画面に1個か2個だけ置きます。

「中」は脇役です。

主役よりも色や書き込みの量に少し差をつけるとなお良いです。

画面の大きさやバランスによりますが、主役より多く、3~5個ほど置くと良いと思います。

「小」はモブです。

画面の賑やかしです。

主役と脇役を配置したあと、余白に置いていきます。

置く数は画面の広さで大幅に変わります。脇役の数より多いこともあれば、少ないこともあります。

オブジェクトの配置

「大」「中」「小」の順に配置していきます。

まず「大」を配置します。

大胆に画面からはみ出るぐらい置くとダイナミックさが出ていいと思います。

2つ以上置く場合は一箇所に固まりすぎないように気をつけ、角度に差をつけます。 

次に「中」を、「大」の間に置いていきます。

こちらも、近くにある「中」同士が似た角度にならないように気をつけます。

最後に「小」を、余った部分に入れていきます。

「小」と「すこし小さめの小」を作って一緒に配置していくとよりランダム感が出ます。

配置の良い例・悪い例

こちらが配置の良い例です。

そしてこちらがあまり良くない例です。

よりいいバランスのランダム配置にするには、下記のポイントに気をつけましょう。

・余白が均等に空きすぎている

タイトルの目立ち感が少ないですね。

また、オブジェクト同士の余白がだいたい同じぐらい空いていて、スカスカしているように見えます。

「粗」(空いているところ)と、「密」(詰まっているところ)が生まれるように配置しましょう。

また、主役の周りは「疎」にすると主役をより目立たせることができます。

・似た要素を似た角度で置かない

「大 A」「大 B」の角度が似ています。

また、「中 a」と「中 B」の角度も似ていますね。

ランダム配置の場合に似た要素が似た角度になると「何らかの意味」があるように感じられて不自然になります。

角度はばらばらになるようにしましょう。

・「触れるか触れないか」はやめる

「大 A」の下、「小」が触れるか触れないかの場所に置いてあります。

この、「触れるか触れないか」というのも「何らかの意味」を生みます。

ちゃんと離すか、ちゃんと重ねるかどちらかにしましょう。

ランダム配置は、「おもちゃ箱を投げたときにおもちゃが床に散らばる感じ」をイメージします。

同じ形のおもちゃが全く同じ角度になる確率はとても低いだろうし、おもちゃとおもちゃの隙間が全部均等になることなんて多分ありませんよね。

作成したランダム配置に沿って、お花を置いてみました。

お花バナー

華やかで可愛い感じにできたと思います!

まとめ

ランダム配置は何度も作っていると、なんとなく感覚でできるようになってきます。

それまでは、

他人に見せる→バランスが悪いと思うところを指摘してもらう

というのを繰り返すといいと思います。

少し休憩を挟んだり、離して見てみたりするのも有効な手です。

1人で作っているとなんだかよくわからなくなってくるので…

(私もしょっちゅうなんだかよくわからなくなっています)

この世に私好みの可愛くてワイワイしたデザインが一つでも増えるといいなと思っていますので、みなさんもどんどんランダム配置を使ったデザインを作ってくださいね〜!(強欲)


お金は大事という話

こんにちわ。
リエです。

4月から新社会人になられた方は初任給を手にしたかと思いますが、使い道を考えてワクワクした方が多かったのではないでしょうか。

わたしは高校生の頃からアルバイトをしていたのでお給与自体は手にしたことはありましたが、社会人として初めて手にしたお給与は、なんというか社会に認められたようでとても嬉しかったのを覚えています。
あと何に使おうか考える時間はめっちゃ楽しかったですw

それと同時に給与明細書にかかれている項目をみて、払うものも多いんだな〜とプチ絶望したのも覚えています。(今はそんなことないよ!)

お金って時に自分の身を守ってくれたり、逆に身を傷つけるものになったりもするわけですが、あるに越したことはない。絶対に。
お金があって困ることはおそらくないから。

ちなみになんでこんなブログを書こうかと思ったかというと、10連休の影響でお財布の中が寂しいからです( ;∀;)
やはりお休みが続くと支出が増える/(^O^)\
でも決して無計画に使ったわけではなく、予想外の支出が多かったのです!
はい、言い訳ですね。。予想外の支出があるかもと予想できなかった自分が悪い。
というわけでこの反省を生かし対策を練るために緊急お金会議をしました。(※1人でです)

その会議で決まったことは、その月使えるお金から先に5千円を抜いて別保管するということ。そしてその5千円はどうするのかというと、お給料日1週間前にお財布に戻します。そうすればお給料日前で大ピンチ!ということがあっても5千円を手にすることができます。5千円あれば予想外のことがあっても1週間は過ごせるはず。

まぁ究極、お金なかったら使わないように生活したらいいやんとなるかもですが、1週間お金使わないとか無理じゃないですか?生きてますもん。

ということでお給料日が待ち遠しいリエでした。

お金は本当に大事。


ゲーム界隈とかが映像表現の最先端かもしれないと思う件


最近のプライベートはゲーム三昧なLQヒロシです。


eスポーツが2022年のアジアオリンピックに採用されることが発表された話題も記憶に新しいゲーム業界。私事になりますが、先日、オンラインゲーム FINAL FANTASY 14のファンフェスティバルに参加してきました。

幕張メッセで2日間行われた大規模イベントには1万5000ものユーザーが参加。イベント内では「光のお父さん」という FINAL FANTASY 14のユーザーを題材にした物語の実写映画化が発表され、有名な俳優さんを壇上で拝見することができ幸せな時間を過ごさせていただきました。

そういった話題性だけでなく、最近のゲームはクオリティの進歩が著しく、映像表現といえば映画やインタラクティブアートなどが評価の対象となっているイメージですが、なんでゲームが注目を浴びないのかが不思議になります。本記事では私的注目のゲーム界隈にまつわるお話をさせていただきます。

まるでフライトシュミレーターのようなプレイ体験


2019年2月にエースコンバットという現実の戦闘機が活躍するシューティングゲームシリーズの最新作がリリースされました。お試し版をダウンロードして会社のPSVRでプレイ!

本作は実際に戦闘機に乗っているのでは?フライトシュミレーターなんじゃない!!?と思うぐらいのクオリティで、Vertigoという天地がわからなくなる現実さながらの現象を体験することができたりします。(実際にプレイしてVertigoになり墜落しましたw)

参照)エースコンバット7
©BANDAI NAMCO Entertainment Inc.


航空自衛隊でフライト経験がある方もブログ記事で絶賛しており、「リアルすぎて(仕事みたいで)面白くない」というブラックジョークな評価をしております。詳しくはこちら

『エースコンバット7』はもはや面白くないフライトゲームへと成り果てた|MY GAME LIFE


3DCGのクオリティの高さをこれでもかと見せつけられる


2018年の作品ではありますが、GOD OF WARという北欧神話を元にしたアクションアドベンチャーゲームではレンダリングの美しさを体験することができます。驚くべきは、その実写のようなクオリティがプレイ画面であるということ。イベントで挿入されるムービーと遜色がなく、かつシームレスに移行するので、始めた当初は少し戸惑うぐらい衝撃を受けました。The Game Awards 2018ではゲーム・オブ・ザ・イヤー、ベストゲームディレクションを受賞しているようです。


下記のトレイラーを見比べていただくとわかりやすいかなと思います。神話を元にしたストーリーをしっかり感じさせる美しいビジュアルと抜群の操作感、爽快感を見事に両立させた非常にやり応えのある作品でした。

©2018 Sony Interactive Entertainment LLC


こちらはバトル紹介のトレイラー

©2018 Sony Interactive Entertainment LLC

参照)プレイステーション公式|ゴッド・オブ・ウォー


アニメーション3DCGの世界と練に練られた最高峰のUI


元々は2016年にプレイステーション3でリリースされた作品がプレイステーション4に移植されたもの。2018年3月31日現在で全世界累計出荷本数は220万本を突破しているヒット作。GOD OF WARと同じ3Dのグラフィックですが、キャラクターがアニメーションのようなテクスチャーで作られたRPGゲームになっています。

©ATLUS ©SEGA All rights reserved.

参照)ペルソナ5


アニメ原画を活かしたキャラクター達がコミカルにシリアスに活き活きと活躍し、実写的な3Dとはまた違う独特な世界観を構築しています。


本作品は多岐にわたる育成要素や攻略要素があり、ゲームシステム的には割と複雑な無類だと思います。そんな複雑なシステムでありながら、いかにユーザーの無駄な作業を限りなく減らすかを考え抜かれていているところが面白く、細部まで練られたUIやゲーム設計は、非常にテンポが良くオリジナリティ溢れるプレイ体験に昇華できているのも見どころです。

『ペルソナ5』のカッコよすぎるUIの制作工程を紹介! アトラスの危機から生まれ、やがて特徴となったUIができるまで【CEDEC+KYUSHU 2017】|ファミ通.com


こういったアニメーションテクスチャーのCG表現は、WEBでも活用されていて、Vtuberやスマートフォンゲームやキャラクター作成で見かけることができます。※LIVE2D、SPINEといったソフトウェアが利用されているようです。

©BANDAI NAMCO Entertainment Inc.

参照)アイドルマスター シャイニーカラーズ(シャニマス)


ゲーム「界隈」ではなく、インタラクティブなアート表現として評価される日も近いのでは


私もそこまでどっぷりゲーム沼に浸かっているわけではありませんが、ちょっと覗くだけでこれだけの表現で溢れているのが驚きです。ビジュアル単体としてのアイデンティティは、アート作品のような特別なコンセプトやアイデンティティがあるわけではありませんが、ゲーム作品としての狙いや表現、技術は目を見張るものがあります。もっと幅広い評価があってしかるべきではないかと個人的には思っています。


最近では、VR上でコミュニケーションを行うプラットフォームなどでもLIVE2Dモデリングのようなアバターが利用されているなどの新しい流れが生まれています。海外で制作されたゲームのローカライズ対応も当たり前になり、クオリティの高い作品がどんどんリリースされています。


ゲームって時間をかなり取られてしまいますが、この流れを完全にスルーするのもちょっともったいないように思います。たまには息抜きがてらゲームをしてみて界隈の動きに注目しても良いのではないでしょうか。








失敗作も成功のもと

こんにちは。開発担当のマットです。

以前に記事を書いた事がありますが、人間をぶっ飛ばす「人間大砲」ゲームを開発しました。

ゲームの内容はとても簡単です。
ボタンを押すと人間が大砲から飛ばされて、タイミング良く押すとより遠くへ飛んでいくという内容です。

人間をぶっ飛ばすことが面白くて楽しいアプリですが、「アンロックできるコンテンツ」や「レベル」というものがないので、公開した時は「すぐ飽きてしまうんじゃないか」とちょっと心配していました。

バージョン2を作ろう!

「人間大砲」をもっと面白くしようと思って、「人間大砲2!」的なプロジェクトを作って開発に取り組みました。
バージョン1と同じように作るけども、以下の2点を加えようと考えました。

  1. 人間がまっすぐに飛ぶだけではなく、もっとアチラコチラに飛び跳ねるようにする
  2. 飛ばす力をレベルアップできるようにする

とても簡単な変更だと思っていましたが、意外な問題が発生しました。

スケーリングの問題

IT用語では「スケーリング」は「規模を増減すること」を指します。
IT業界では、とても大事な概念です。
アプリケーションやシステムが大きくなるに連れ、どの問題に当たるかを事前に考えて対応をしなければなりません。

しかし、シングルプレイヤーのゲームだと、特に問題はないだろうと思って簡単なプロトタイプを作成してみたら・・・ 意外な問題にぶち当たりました。

人間がさらにアチラコチラに飛び跳ねる様になると大きく左右に飛ぶことになります。
特に問題はないと思っていましたが、バージョン1では1本道で十分足りていたことに対してバージョン2では、横の道まで行くことが可能になりますので、格子状の街を作らなければならないことになります。

ある意味「1次元の世界」が「2次元の世界」に変わります。
一つの設計変更で、次元を増やしてしまいました。

なお、バージョン2ではレベルアップができるので、トップレベルのパワーで飛ぶと建物の上まで飛んで遠くまで見ることが可能になります。

バージョン1では、近くのエリアだけをロードすれば十分でしたが、もっと高いところまで飛ぶと遠くまで見えてしまいます。その分も端末のメモリーにロードしなければなりませんが、そうするとパフォーマンスがグッと落ちてしまい、逆にストレスがたまるゲームになってしまいます。

見ての通り、同時にロードをしなければならない内容の量が全然違います

ゲーム性の問題

次の問題は技術的な壁ではなくて、ゲーム性の問題でした。

レベルアップができるようになるとより遠くに飛べるようになりましたが、パワフルな勢いで建物や障害物を変わった角度で当ててしまうと上までなが〜く飛んでしまいます。

その結果、空に飛んでいる間は障害物に当たることなく、緊張感もなく、なにも起こらない全然面白くないゲームになってしまいました。

ただ単に飛んでいるだけ・・・

気軽に作ろうと思っていたプロジェクトが、色々と問題が出てしまったので一旦棚上げすることにしました。
またいつか、人間大砲の改善バージョンを作りたいと考えていますが、とりあえず上記で作ったバージョン2は失敗作と見做したいと思います。

失敗で習ったこと

この記事を読んでいただいておわかりかと思いますが、ちょっとした変更でも最終的には大きな影響を及ぼすことがあります。

やっぱり、設計が大事!

ゲームを設計する時、「より大きい」「よりパワフル」「より広い」ことは必ずしも良いとは言えません。
今後、ゲームを設計する時はそのゲームに合っている内容量、そのゲームに合っている規模をきちんと考えて作らなければなりません。

習ったことを活用する

ちょうど、同じ頃にゾンビゲームも作っていました。
走り回って、ゾンビを倒して、生存者を救うという単純な内容ですが、面白くてハマってしまうジャンルです。

まずはマップを作成する必要がありました。
当初はやっぱり、「大きく、広く、膨大!」という気持ちで作りだしました。

膨大なマップを作っていた頃のスクリーンショット

横切れる山もあり、川と橋もマップに入れて、作ってみました。

しかし、人間大砲バージョン2で学んだことで、以下の懸念点に気が付きました。

  1. マップが広いと、走る距離も長くなり面白くなくなる。
  2. コンテンツをまばらにしないとパフォーマンス問題に当たる。
  3. マップに登れる山などがあると、新しい次元(上下向き)も対応しなければならない。

なお、モバイルではマウスが使えないので、左手の親指で前後移動と左右向きの操作をし、右手の親指で武器の操作を行う場合は、上下向きを操作する余裕はありませんでした。

やっぱり、設計が大事!

上記の懸念点を踏まえてマップを作り直すことにしました。
マップ自体を狭くし、その分コンテンツに密度を入れることができました。
登ったり下ったりできる個所を完全になくして、平面で遊べるようにしました。

作り直したマップ(実際にプレイできるエリアは街周りだけです)

最終的にこれらの変更のお陰で緊張感のある面白いゾンビーゲームを作ることに成功しました。

まとめ

昔、ある有名な航空設計士がこんなことを言いました。

完璧という状態は、何も加えるものがなくなったときではなく、何も除く必要がなくなったときに達成されるものだ。

ゲーム作成やソフトウェア設計でも同じかもしれません。
開発者としてはもっともっとと色々コンテンツや機能を盛り上げたくなりますが、盛り上げすぎるとそのソフトが逆に目的を果たさなくなってしまうこともあります。

今後も、このことをより把握した上で色々な面白いものを作っていきたいと思います!