【发布时间】:2018-03-04 20:25:26
【问题描述】:
我有一个看起来差不多的模型(在 JSON 中):
{"gender": "female",
"name": [
{"family": "Smith",
"given": ["Samantha"],
"middle": ["Lee"]]}}
这种结构的记录大约有 6M 条。我需要使用 OR 子句对人名的所有组成部分进行全文搜索。例如。如果用户输入“smith”,我需要检查所有给定、中间名和姓氏。
在 Datomic 中,我创建了一个模式:
{:db/ident :model/name
:db/valueType :db.type/ref
:db/isComponent true
:db/cardinality :db.cardinality/many}
{:db/ident :model.name/family
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one
:db/fulltext true}
{:db/ident :model.name/given
:db/valueType :db.type/string
:db/cardinality :db.cardinality/many
:db/fulltext true}
{:db/ident :model.name/middle
:db/valueType :db.type/string
:db/cardinality :db.cardinality/many
:db/fulltext true}
注意,我为这些属性提供了全文索引。现在,当我通过单个属性查询时,例如 family,性能非常好(大约 100 毫秒):
(def query-all
'[:find [(rand 100 ?model) ...]
:in $ ?search
:where
[(fulltext $ :model.name/family ?search) [[?name _ _ _]]]
[?model :model/name ?name]])
但是当我使用 OR 子句添加其他条件时,性能急剧下降(20 秒):
(def query-all
'[:find [(rand 100 ?model) ...]
:in $ ?search
:where
(or
[(fulltext $ :model.name/family ?search) [[?name _ _ _]]]
[(fulltext $ :model.name/given ?search) [[?name _ _ _]]]
[(fulltext $ :model.name/middle ?search) [[?name _ _ _]]])
[?model :model/name ?name]])
我的问题是,我该如何改进?
如果我们更进一步,不仅可以通过名称查找,还可以通过地址的组成部分查找,这将是非常棒的。理想情况下,会有以下查询(运行速度也很慢):
(def query-all
'[:find [(rand 100 ?model) ...]
:in $ ?search
:where
(or
(and
[(fulltext $ :model.name/given ?search) [[?e _ _ _]]]
[?p :model/name ?e])
(and
[(fulltext $ :model.name/middle ?search) [[?e _ _ _]]]
[?p :model/name ?e])
(and
[(fulltext $ :model.name/prefix ?search) [[?e _ _ _]]]
[?p :model/name ?e])
(and
[(fulltext $ :model.name/suffix ?search) [[?e _ _ _]]]
[?p :model/name ?e])
(and
[(fulltext $ :model.name/family ?search) [[?e _ _ _]]]
[?p :model/name ?e])
(and
[(fulltext $ :model.address/city ?search) [[?e _ _ _]]]
[?p :model/address ?e])
(and
[(fulltext $ :model.address/state ?search) [[?e _ _ _]]]
[?p :model/address ?e]))])
我将如何实现这个?
【问题讨论】: