调整Sphinx搜索以进行产品搜索


Tuning Sphinx search for product search

我们有一个非常简单的产品目录,它将产品存储在mysql表中,我们需要为应该尽可能快(并且尽可能相关)工作的产品建立一个高质量的搜索。产品数据库将相当大(约500000个产品),这就是为什么使用"赞"而不使用索引的搜索速度非常慢的原因。我们已经尝试过使用mysql全文搜索,它工作得很快,但没有产生令人满意的结果,尤其是对于使用数字的搜索(例如"LR-41",这是一种电池类型等)

我们的产品目录包括许多字段,但我们唯一需要搜索的是:

product_id = bigint
title = varchar(255)
description = text

经过多次建议,我们最终尝试使用Sphinx搜索,并进行了如下配置:

source mysearch {
  type=mysql
  sql_host=...
  sql_user=...
  sql_pass=...
  sql_port=...
  sql_query_pre = SET NAMES utf8
  sql_query = SELECT product_id, title, description FROM products
  sql_query_info = SELECT * FROM products WHERE product_id=$id 
}
index fulltext { 
    source  = mysearch
    path = /var/lib/sphinxsearch/data/mysearch
    docinfo = extern
    mlock = 0
    morphology = stem_en, metaphone
    min_word_len = 1
    blend_chars = +, &, U+23, -
    blend_mode = trim_both
    html_strip = 1 
}
indexer {
    mem_limit = 256M 
}
searchd {
    listen = 9312 
    # everything else set to default
}

对于网站后端,我们使用PHP,并使用以下代码:

<?php
$sphinx = new SphinxClient();
$sphinx->SetServer('localhost', 9312);
$sphinx->SetMatchMode(SPH_MATCH_EXTENDED);
$sphinx->setFieldWeights(array(
    'product_id' => 10,
    'title' => 7,
    'description' => 3
));
$sphinx->setLimits(0, 200, 1000, 5000);
$sphinx->SetRankingMode(SPH_RANK_PROXIMITY_BM25);
$sphinx->AddQuery($_GET['query'], "fulltext");
$results = $sphinx->RunQueries();
print_r($results);
?>

这只是一个测试搜索的演示脚本,但无论我用来查询什么,它都会返回完全错误的结果——它匹配的产品甚至不包括我正在搜索的单词(或子字符串)。

以下是我想要实现的规则:

  • 如果查询与"product_id"匹配,则该产品应排名最高(一些经常使用product_id的用户希望通过它进行搜索)
  • 如果查询是"Meter XY-123",它应该匹配包含这两个词或其中任何一个词的所有产品(当然,包含这两种字符串的产品应该排名更高)
  • 如果在标题中找到查询,则其排名应高于在描述中找到查询的排名
  • 如果有人搜索"XY-123",其结果应该与搜索"XY123"或"XY123
  • 它还应该搜索子字符串-例如,如果产品的标题是"Foobar 123",即使用户搜索"foo bar 123"、"bar 123"answers"foo"等,也应该返回它
  • 结果也应该按某种相关性排序返回。。例如,如果我有两个产品"foobar 123"answers"foobar 456",并且用户搜索"foobar 4",那么这两个产品都应该返回(匹配任何单词),但第二个产品的排名应该比第一个产品(不包含数字4)高(因为它也包含数字4。)
  • 产品还应该根据值所在的字段进行排名。在这种情况下,product_id字段的权重大于title,title的权重也高于description

所以问题是——如何正确配置和使用sphinx+php来生成符合上述标准的搜索结果?

谢谢!

这只是一个测试搜索的演示脚本,但无论我用于查询,它都会返回完全错误的结果

建议从morphology中删除metaphone。这特别允许"模糊"索引——有点像"声音相似"。但它不能很好地与词干(即stem_en)结合使用,这会导致非常令人困惑的结果。

事实上,如果你设置前缀索引(见下文),你可能也可以删除词干——如果同时尝试和使用这两种方法,很难检测边缘情况。


如果查询与"product_id"匹配,则产品应排名最高(一些经常使用产品id的用户希望通过它进行搜索)

Sphinx在"全文"索引中不包括产品id。你需要复制它。

sql_query = SELECT product_id as id, product_id, name,...  

如果查询是"Meter XY-123",它应该匹配所有包含这两个词或其中任何一个词的产品(当然,包含这两种字符串的产品应该排名更高)

这意味着您要进行"任意"搜索。Sphinx默认为"ALL"搜索。更改为SPH_MATCH_ANY,或重写查询使其为"ANY"(在单词之间注入"|"或使用quorum)


如果有人搜索"XY-123",应该会产生与搜索"XY123"或"XY123"相同的结果

这真是涓涓细流。您可以尝试将-添加到blend_chars。这会起作用的。但是输入say"XY123"将不匹配带有"XY123"的产品。我认为没有简单的解决办法。

有各种各样的统计方法试图重写查询,但从本质上讲,它们是不精确的。


它还应该搜索子字符串-例如,如果产品的标题是"Foobar 123",即使用户搜索"foo bar 123"、"bar 123"answers"Foobar 12"、"foo"等,也应该返回。

需要使用min_prefix_len来启用前缀搜索,并设置enable_star = 0

但是enable_star=0是非关联的,所以也许可以使用expand_keywords=1,它会自动为您添加星星。


还应按某种相关性的顺序返回结果

总的来说,这是会发生的。但如果需要,可以尝试更改排名模式-有很多选项(但需要使用扩展匹配模式)


产品还应该根据价值所在的字段进行排名。

setFieldWeights到救援!(你已经得到了!)