全文搜索(基于Tantivy的FTS)
LanceDB还通过Tantivy提供全文搜索支持,使您能够在检索解决方案中集成基于关键词的搜索(基于BM25算法)。
基于tantivy的全文搜索(FTS)仅支持Python同步API,不支持在对象存储上构建索引或增量索引。如需这些功能,请尝试原生FTS native FTS。
安装
要使用全文搜索功能,请安装依赖项 tantivy-py:
示例
假设我们有一个名为my_table的LanceDB表,其字符串列content需要通过关键词搜索进行索引和查询,在使用关键词搜索前必须先创建FTS索引。
import lancedb
uri = "data/sample-lancedb"
db = lancedb.connect(uri)
table = db.create_table(
"my_table",
data=[
{"id": 1, "vector": [3.1, 4.1], "title": "happy puppy", "content": "Frodo was a happy puppy", "meta": "foo"},
{"id": 2, "vector": [5.9, 26.5], "title": "playing kittens", "content": "There are several kittens playing around the puppy", "meta": "bar"},
],
)
# passing `use_tantivy=False` to use lance FTS index
# `use_tantivy=True` by default
table.create_fts_index("content", use_tantivy=True)
table.search("puppy").limit(10).select(["content"]).to_list()
# [{'text': 'Frodo was a happy puppy', '_score': 0.6931471824645996}]
# ...
默认情况下,它会在所有已建立索引的列上进行搜索,因此在存在多个索引列时非常有用。
注意
如果搜索输入的类型是str,LanceDB会自动在现有的全文搜索索引上进行搜索。如果提供向量作为输入,LanceDB则会转而搜索近似最近邻索引。
分词
默认情况下,文本会通过标点符号和空格进行分词,并移除长度超过40个字符的词元。如需支持特定语言的分词处理,请提供参数tokenizer_name,格式为双字母语言代码加上"_stem"后缀。例如英语对应的是"en_stem"。
目前支持以下语言。
为多列建立索引
如果您有多个字符串列需要索引,无需手动合并它们——只需将它们全部作为列表传递给create_fts_index:
请注意,搜索API调用保持不变 - 您可以一次性在所有索引列上进行搜索。
筛选
目前LanceDB全文搜索功能支持后过滤,意味着过滤器会应用于全文搜索结果之上(如需预过滤请参阅native FTS)。这可以通过熟悉的where语法调用:
排序
你可以在创建全文搜索索引时通过指定ordering_field_names来预先对文档进行排序。一旦预先排序完成,你就可以在搜索时指定ordering_field_name来返回按给定字段排序的结果。例如,
table.create_fts_index(["content"], use_tantivy=True, ordering_field_names=["id"], replace=True)
(table.search("puppy", ordering_field_name="id")
.limit(20)
.to_list())
注意
如果想在查询时指定排序字段,则必须在索引创建阶段也定义该字段。否则查询时会报错,提示类似ValueError: The field does not exist: xxx
注意
用于排序的字段必须是无符号整数类型,否则在索引过程中会出现类似TypeError: argument 'value': 'float' object cannot be interpreted as an integer的错误。
注意
您可以在索引时指定多个排序字段。但在查询时仅支持一个排序字段。
短语查询与术语查询对比
要进行全文搜索,您可以指定短语查询如"the old man and the sea",
或者术语搜索查询如"(Old AND Man) AND Sea"。有关术语查询语法的更多详细信息,请参阅Tantivy的查询解析器规则。
注意
查询解析器会对存在歧义的查询抛出异常。例如,在查询they could have been dogs OR cats中,OR是大写的,因此被视为关键字查询运算符。但左侧部分的处理方式存在歧义。因此如果直接提交这个搜索查询,你会得到Syntax Error: they could have been dogs OR cats错误。
另一方面,将OR转换为小写的or是可行的,因为不存在大写的逻辑运算符,查询会被视为短语查询。
根据您想要执行的查询类型,记住哪些操作会导致语法错误可能会很麻烦。为了简化这一点,当您想要执行短语查询时,可以通过以下两种方式之一强制执行:
- 将双引号包裹的查询语句放在单引号内。例如,
table.search('"they could have been dogs OR cats"')会被视为短语查询。 - 显式声明
phrase_query()方法。当您的短语查询本身包含双引号时,这非常有用。例如,table.search('the cats OR dogs were not really "pets" at all').phrase_query()会被视为短语查询。
通常情况下,声明为短语查询的语句在解析时会被双引号包裹,其中嵌套的双引号会被替换为单引号。
配置
默认情况下,LanceDB为创建索引配置了1GB的堆内存大小限制。如果在较小节点上运行,可以降低此值;若需在索引较大语料库时获得更快性能,则可增加此值。
# configure a 512MB heap size
heap = 1024 * 1024 * 512
table.create_fts_index(["title", "content"], use_tantivy=True, writer_heap_size=heap, replace=True)
当前限制
-
创建FTS索引后新增的数据会出现在搜索结果中,但由于需要对未索引部分进行平面搜索,会导致延迟增加。使用
create_fts_index重新索引可以降低延迟。LanceDB Cloud自动执行此合并过程,将对搜索速度的影响降至最低。 -
目前我们仅支持本地文件系统路径用于FTS索引。 这是tantivy的一个限制。我们已经实现了一个对象存储插件, 但在tantivy-py中无法指定使用它。