データベース (RDB) と比べた際の Algolia の気になった点
検索機能を提供する Algolia について
データベースの機能と比較した際に気になった点を書いてみます。
当記事の内容は 公式のドキュメント に書いてあることなので
正確な情報はそちらを確認するようしてください。
Algolia の使用感がわかる Live Demo (InstantSearch)
Index
には環境識別子をつけましょう
All Environments on the Same Application
RDB でのテーブルに近い位置となる Index
ですが、
同一の application
に複数の環境のものを用意したほうがよいとされています。
products
とすると dev_products
, staging_products
, prod_products
などですね。
Unless you are on an Enterprise plan and have a dedicated cluster of servers, having multiple applications generate an invoice per application.
これは実装上での必要性というか 「application ごとに環境を分けてもいいけどそれぞれに請求が行くよ」 という記述によるところです。
演算子について
等号
RDB の SQL の WHERE
に該当するといえる Algolia の Filtering にて使用する =
などの等号に差が・・・
-- 文字列
column_1 = '対象文字列'
-- 数字
column_2 = 123
これが Algolia の場合には以下のようになります。
文字列の場合 :
を使用
Algolia の通常の検索 (入力などに対して近しいレコードを上位に位置させる) でなく、
SQL の WHERE
のように一致しない候補を結果から外すには
文字列の場合に attributesForFaceting
の設定が必要です。
Configuring attributesForFaceting
index.setSettings({
attributesForFaceting: [
'brand' // or 'filterOnly(brand)' for filtering purposes only
]
})
これで brand
に対して Filtering が可能となり、以下で Motorola
のものを抽出します。
Applying a string filter
// Only “Motorola” smartphones
index.search('smartphone', {
filters: 'brand:Motorola'
})
数字
boolean
の場合 =
を使用
Filter By Numeric Value
Filter By Boolean
Algolia では数字 (とみなされる値) については =
を使用します。
また、文字列において必要となっていた attributesForFaceting
の設定は不要です。
1. Define attributes that need to be filterable (at indexing time)
Note that if you need to filter on numeric or boolean attributes, you don’t need to set them as attributesForFaceting.
以下にてそれぞれの抽出を行っています。
-
price
が100
のもの -
is_available
がtrue
のもの-
true
は1
-
false
は0
-
index.search('query', {
filters: `price = 100`
})
・・・
index.search('query', {
filters: `is_available=1`
})
BETWEEN
price BETWEEN 100 AND 200
数字でも BETWEEN
のような記述については :
も使用するようです。
index.search('query', {
filters: 'price:100 TO 200'
})
値の型のバリエーションを考慮した関数
前述の通り、文字列と数値で等号にバリエーションがあるため、
それを吸収するための関数を用意しておくとよいかもしれません。
/**
* 文字列、数字の等号の指定を吸収する関数
* @param {string} attr 評価対象の `Attribute`
* @param {string | number} val 評価対象の `Attribute` の値
* @return {string} `attr=val` or `attr:val`
*/
const equal = (attr, val) => {
const operator = typeof val === 'string' ? ':' : '='
return [attr, operator, val].join('')
}
配列への検索
Algolia は Index
の Record
に配列も格納することができるので、それに対する Filtering
も可能です。
配列の要素が 文字列であれば attributesForFaceting の設定が必要 です。
以下では categories
に politics
が含まれているものを抽出します。
index.search('harry', {
filters: 'categories:politics'
})
逆に politics
が含まれていないもの が欲しい場合 NOT
による否定で実現が可能です。
index.search('harry', {
filters: 'NOT categories:politics'
})
要素が数字である場合 attributesForFaceting
が不要で、演算子は =
を使用します。
index.search('harry', {
filters: 'types = 123'
})
AND
OR
NOT
について
内容については Filters and Boolean Operators のピックアップなので詳細はリンクを確認してください。
また、記述が正しいかの確認が Filters syntax validator により可能です。
AND
, OR
それぞれの単体については SQL の使用と変わりません。
条件の 論理積
論理和
が求められます。
The following operators, which must be specified in CAPS
ただし使用する際には や and
など小文字を含まない、すべて大文字である必要があるようです。Or
以下においては AND
により条件が結合されています。
-
category
がBook
かEbook
であり (OR
) -
author
がJK Rowling
でないもの (NOT
)
index.search('', {
filters: '(category:Book OR category:Ebook) AND NOT author:"JK Rowling"'
})
(category = 'Book' OR category = 'Ebook')
AND
NOT author = 'JK Rowling'
AND OR に対して Algolia での注意事項
(A AND B)
など括弧でグループ化した条件は NOT
で否定できない
You cannot negate a group of filters, only an individual filter. For example, NOT(filter1 OR filter2) is not allowed.
()
によりグループ化した複合条件に対して NOT
により否定することができません。
index.search('', {
// これはダメ
filters: 'NOT (author:"JK Rowling" AND author:"JRR Tolkien")'
})
括弧による条件のグループ化に制約あり
For performance reasons, we do not allow you to put groups of ANDs within ORs.
AND
でグループ化した結果を OR
でさらに再グループ化をすることを許可していないとのことです。
We allow ( x AND (y OR z) AND (a OR b) )
OR
をグループ化したものを AND
で再グループ化なので OK
We allow ( x AND y OR z AND a OR b )
グループ化してないので OK
We don’t allow
( x OR ( y AND z) OR ( a AND b) )
AND
でグループ化された ( y AND z)
, ( a AND b)
を含んで OR
により結合しているため NG
We don’t allow
(a AND b) OR (c AND d)
AND
でグループ化した条件のみで OR
による再グループ化を行っているため NG
括弧は補完される
以下のような AND
と OR
が混ざっているケースでは OR
の部分で勝手にグループ化されるようです。
( x AND y OR z AND a OR b ) becomes ( x AND (y OR z) AND (a OR b) )
( x OR y AND z OR a AND b ) becomes ( (x OR y) AND (z OR a) AND b )
Given the potential for confusion, we encourage you to use parenthesis.
「Algolia 側で括弧は付加されるので混乱しないよう括弧はつけるようにしたほうがいいですよ」
複数の型を OR
で結合は不可
Mixing type of filters in OR conditions
OR
により型の違う条件をグループ化することはだめとのことです。
For example,
num=3 OR tag1 OR facet:value
is not allowed.
数字の num=3
, Boolean の tag1
, 文字列の facet:value
となりだめなようです。
Records
の格納先はテーブルではなく Index
The Index
RDB ではテーブルにレコードを格納しますが、 Algolia での格納先は Index
となります。
JOIN
とかはなく Index
の Record
に必要に応じて非正規化を行って突っ込むようです。
ORDER BY
そんなものウチにはないよ・・・
Algolia では問い合わせ時に Index
への並べ替え を要求できません。
しかし並べ替え自体は当然可能です。
ただし並べ替えの前提として Replica
の概念を知る必要があります。
Replica
についてはざっくりと以下の通りです。
-
Index
をコピーしたものがReplica
-
Index
のデータであるRecords
の登録
・更新
・削除
はReplica
に同期される -
Replica
は 並べ替えなどの独自の設定を持つことができる
つまり・・・
SQL では ORDER BY
により並べ替えを行うことができますが
ORDER BY
price ASC -- or `price DESC` で降順へ
Algolia では以下のような対応が必要となります。
-
price
の降順の並べ替えを行いたい場合、Replica
を作成し並べ替え設定にprice
を設定- 元の
Index
がproducts
であればReplica
としてproducts_price_desc
を作成 - 並べ替え設定に
price
の降順となる設定を追加
- 元の
-
検索を行う際に 検索対象を products から products_price_desc へ切り替えを行う