【问题标题】:Tuning Sphinx search for product search调整 Sphinx 搜索产品搜索
【发布时间】:2013-12-12 23:18:00
【问题描述】:

我们有一个非常简单的产品目录,将产品存储在 mysql 表中,我们需要为应该尽快工作(并且尽可能相关)的产品构建高质量搜索。产品数据库将非常大(大约 500.000 个产品),这就是为什么使用“like”而不使用索引的搜索非常慢的原因。我们已经尝试过使用 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”或“XY 123”相同的结果
  • 它也应该搜索子字符串 - 例如如果产品的标题是“Foobar 123”,即使用户搜索“foo bar 123”、“bar 123”、“foobar 12”、“foo”等,它也应该返回。
  • 结果也应该按某种相关性排序。例如如果我有两个产品“foobar 123”和“foobar 456”并且用户搜索“foobar 4”,那么这两个产品都应该返回(匹配任何单词)但是第二个产品应该排名更高(因为它也包含数字 4)比第一个(不包含数字 4)。
  • 还应根据值所在的字段对产品进行排名。在这种情况下,product_id 字段的权重大于标题,标题的权重也高于描述。

那么问题来了——如何正确配置和使用sphinx + php来产生符合上述条件的搜索结果?

谢谢!

【问题讨论】:

    标签: php search sphinx


    【解决方案1】:

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

    建议从morphology 中删除metaphone。这特别启用了“模糊”索引 - 有点像“听起来相似”。但它与词干(即stem_en)结合起来效果不佳 - 导致非常混乱的结果。

    事实上,如果您设置前缀索引(见下文),您也许也可以删除词干 - 如果尝试同时使用这两种情况,则很难检测到边缘情况。


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

    Sphinx 在“全文”索引中不包含产品 ID。你需要复制它。

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

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

    这意味着您要进行“任何”搜索。 Sphinx 默认为“全部”搜索。更改为SPH_MATCH_ANY, 或重写查询以使其成为“ANY”(在单词之间插入“|”或使用仲裁)


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

    这很棘手。您可以尝试将 - 添加到 blend_chars。哪个会起作用。但是输入“XY 123”不会匹配带有“XY123”的产品。我不认为有一个简单的解决方案。

    有各种各样的统计方法可以尝试重写查询,但它们的本质是不精确的。


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

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

    enable_star=0 已被淘汰,所以也许可以改用expand_keywords=1,它会自动为您添加星标。


    结果也应该按某种相关性排序

    通常会发生这种情况。但是如果需要可以尝试更改排名模式 - 有很多选项(但需要使用扩展匹配模式)


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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-06-04
      • 1970-01-01
      • 1970-01-01
      • 2021-10-23
      • 2014-07-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多