Solrのjoinとblock joinについて

MySQLの場合

regions

id name
1 US
2 ASIA

products

id name brand_id_s
1 iPhone 1
2 iPad 1
3 Galaxy S3 2
4 Galaxy Note 2
5 one X 3

brands

id name region_id_s
1 Apple 1
2 Samsung 2
3 HTC 2

products.name が iPad の brands を検索

JOINでこんなかんじ

mysql> SELECT brands.* FROM brands
    ->        INNER JOIN products ON brands.id=products.brand_id_s
    ->        WHERE products.name="iPad";
+------+-------+-------------+
| id   | name  | region_id_s |
+------+-------+-------------+
|    1 | Apple |           1 |
+------+-------+-------------+
1 row in set (0.00 sec)

mysql>

products.name が iPad の brands がある region を検索

もうちょい複雑なJOINでこんなかんじ

mysql> SELECT regions.* FROM regions
    ->       INNER JOIN brands ON regions.id=brands.region_id_s
    ->       INNER JOIN products ON brands.id=products.brand_id_s
    ->   WHERE products.name="iPad";
+------+------+
| id   | name |
+------+------+
|    1 | US   |
+------+------+
1 row in set (0.00 sec)

mysql>

ここまでは普通です。とは言ってもSQLを普段書かないので、すぐにJOINでこんがらがります。

Solr の JOIN(block joinではない)の場合

brands

id name
1 Apple
2 Samsung
3 HTC

※ brands に resion_id_s がないのは使わないので付け忘れてました

products

id name brand_id_s
1 iPhone 1
2 iPad 1
3 Galaxy S3 2
4 Galaxy Note 2
5 one X 3

ただし、それぞれのフィールドごとに_versionが付く

products.name が iPad の brands を検索

/solr/brands/select?q=:&fq={!join from=brand_id_s to=id fromIndex=products}name:iPad

<?xml version="1.0" encoding="UTF-8"?>
<response>

<lst name="responseHeader">
  <int name="status">0</int>
  <int name="QTime">1</int>
  <lst name="params">
    <str name="indent">true</str>
    <str name="q">*:*</str>
    <str name="_">1404925101638</str>
    <str name="wt">xml</str>
    <str name="fq">{!join from=brand_id_s to=id fromIndex=products}name:iPad</str>
  </lst>
</lst>
<result name="response" numFound="1" start="0">
  <doc>
    <str name="id">1</str>
    <str name="name">Apple</str>
    <long name="_version_">1473164065209581568</long></doc>
</result>
</response>

products.name が iPad の brands がある region を検索

3つ以上のjoinはできない

Solr の BLOCK JOIN の場合

blocks (brandsとproductsをJOINすることを前提として作成)

parents を持つものにのみ _version が付く (区切りがブロック単位)

id name type_s
1 Apple parents
1 iPhone
2 iPad
id name type_s
2 Samsung parents
3 Galaxy S3
4 Galaxy Note
id name type_s
3 HTC parents
5 one X

products.name が iPad の brands を検索

(iPadのparentsを検索)

/solr/blocks/select?q=:&fq={!parent which=type_s:parent}+name:iPad

<?xml version="1.0" encoding="UTF-8"?>
<response>

<lst name="responseHeader">
  <int name="status">0</int>
  <int name="QTime">1</int>
  <lst name="params">
    <str name="indent">true</str>
    <str name="q">*:*</str>
    <str name="_">1404923918712</str>
    <str name="wt">xml</str>
    <str name="fq">{!parent which=type_s:parent}+name:iPad</str>
  </lst>
</lst>
<result name="response" numFound="1" start="0">
  <doc>
    <str name="id">1</str>
    <str name="type_s">parent</str>
    <str name="name">Apple</str>
    <long name="_version_">1473164315527741440</long></doc>
</result>
</response>

wblocks (brandsとproductsとregionsをJOINすることを前提として作成)

grand_parents を持つものにのみ _version が付く (区切りがブロック単位)

id name type_s
1 US grand_parents
1 Apple parents
1 iPhone
2 iPad
id name type_s
2 Asia grand_parents
2 Samsung parents
3 Galaxy S3
4 Galaxy Note
3 HTC parents
5 one X

products.name が iPad の brands を検索

(iPadのparentsを検索) /solr/blocks/select?q=:&fq={!parent which=type_s:parent}+name:iPad

<?xml version="1.0" encoding="UTF-8"?>
<response>

<lst name="responseHeader">
  <int name="status">0</int>
  <int name="QTime">0</int>
  <lst name="params">
    <str name="indent">true</str>
    <str name="q">*:*</str>
    <str name="_">1404924377347</str>
    <str name="wt">xml</str>
    <str name="fq">{!parent which=type_s:parent}+name:iPad</str>
  </lst>
</lst>
<result name="response" numFound="1" start="0">
  <doc>
    <str name="id">1</str>
    <str name="type_s">parent</str>
    <str name="name">Apple</str></doc>
</result>
</response>

products.name が iPad の brands がある region を検索

(iPadのgrand_parentsを検索)

/solr/wblocks/select?q=:&fq={!parent which=type_s:grand_parent}+name:iPad

<?xml version="1.0" encoding="UTF-8"?>
<response>

<lst name="responseHeader">
  <int name="status">0</int>
  <int name="QTime">1</int>
  <lst name="params">
    <str name="indent">true</str>
    <str name="q">*:*</str>
    <str name="_">1404924542233</str>
    <str name="wt">xml</str>
    <str name="fq">{!parent which=type_s:grand_parent}+name:iPad</str>
  </lst>
</lst>
<result name="response" numFound="1" start="0">
  <doc>
    <str name="id">1</str>
    <str name="type_s">grand_parent</str>
    <str name="region_s">US</str>
    <long name="_version_">1473164347482046464</long></doc>
</result>
</response>

いがいとJOINってできるもんですね(白目)

この blockjoin って cloud datastore でできないかなあというのが本題です。 ちょっとだけ、joinについてまとめてみようと思ったらえらいことになってしまった。