mike-neckのブログ

Java or Groovy or Swift or Golang

datomicチュートリアル13日目 #datomic

今日はfulltextについてやります。

fulltextとは?

:db/valueType:db.type/stringのものについて、保存されている文字列の中から、特定の文字列を含むものを検索することができるようにする機能です。このオプションをattributeに対して設定する場合のスキーマ定義は次のようになります。

[
  {
    :db/id #db/id[:db.part/db -100],
    :db/ident :license/line,
    :db/cardinality :db.cardinality/one,
    :db/valueType :db.type/string,
    :db.install/_attribute :db.part/db,
    :db/fulltext true
  }
]

では次のようなapache license2のテキストをデータに流し込んで、fulltextサーチをしてみたいと思います。

[
  [:db/add, #db/id[:db.part/user], :license/line, "licensed under the apache license version2.0(the"license")"],
  [:db/add, #db/id[:db.part/user], :license/line, "you may not use this file except in compliance with the license"],
  [:db/add, #db/id[:db.part/user], :license/line, "you may obtain a copy of the license at"],
  [:db/add, #db/id[:db.part/user], :license/line, "http://www.apache.org/licenses/license-2.0"],
  [:db/add, #db/id[:db.part/user], :license/line, "unless required by applicable law or agreed to in writing software"],
  [:db/add, #db/id[:db.part/user], :license/line, "distributed under the license is distributed on an "as is" basis"],
  [:db/add, #db/id[:db.part/user], :license/line, "without warranties or conditions of any kind either express or implied"],
  [:db/add, #db/id[:db.part/user], :license/line, "see the license for the specific language governing permissions and"],
  [:db/add, #db/id[:db.part/user], :license/line, "limitations under the license"]
]

fulltextサーチの条件は"license"を含むことです。そのクエリーは次のようになります。

[
:find
    [?line ...]
:where
    [?l :license/line ?line]
    [(fulltext $ :license/line "license") [[?l ?line]]]]

では以下のコードで実行してみます。

List<Map> schemaTx = ... //(transaction data structure for schema)
List list = [...] // Apache license 文章の各行
List tx = list.collect{convertToDbAdd(it)}//(transaction data structure for data)
String query = ...//(クエリー)

@Test
void fulltextをつけてみる() {
    // スキーマ定義
    connection.transact(schemaTx).get()
    // データ登録
    connection.transact(tx).get()

    // db取得
    def db = connection.db()
    // クエリー発行
    def results = Peer.query(query, db)

    //テスト
    assert results.size() == list.findAll{it.contains('license')}.size()
    // 7件になる
    log "size: [${results.size()}]"
}

これを実行すると、テストはパスして、次のようなログが出力されます。

size: [7]

というわけで、保存されているデータに対して指定した文字列を含むレコードが検索できるという機能をfulltextは提供します。

fulltextを付けないとどうなるの?

そこで気になるのが、fulltextを付けない場合です。

上記のスキーマ定義を下記のように書き換えてみましょう。

[
  {
    :db/id #db/id[:db.part/db -100],
    :db/ident :license/line,
    :db/cardinality :db.cardinality/one,
    :db/valueType :db.type/string,
    :db.install/_attribute :db.part/db
  }
]

このスキーマ定義を用いて次のようにテストコードを記述します。

List<Map> schemaTx = ... //(transaction data structure for schema)
List list = [...] // Apache license 文章の各行
List tx = list.collect{convertToDbAdd(it)}//(transaction data structure for data)
String query = ...//(クエリー)

@Test
void fulltextをつけてみる() {
    // スキーマ定義
    connection.transact(schemaTx).get()
    // データ登録
    connection.transact(tx).get()

    // db取得
    def db = connection.db()
    // クエリー発行
    def results = Peer.query(query, db)

    //テスト
    assert results.size() == 0
    // 0件になる
    log "size: [${results.size()}]"
}

これを実行するとテストはパスして、次のようなログが表示されます。

size: [0]

つまり、スキーマ定義の際にfulltextを指定していない場合は、関数fulltextを指定しても、全文一致で検索をしてしまうようです。


なお、fulltextを指定した場合は、そのアトリビュート用にfulltextインデックスが生成されるので、データストアのデータ量が若干増えます。


おわり。

次回は:db/uniqueについてやります。