0

我在 Laravel 4 中实现了以下关键字搜索:

// Search by keyword(s)
if(Input::get('keyword'))
    {
    $search = Input::get('keyword');
    $searchTerms = explode(' ', $search);

    $fields = array(
        'resources.name',
        'resources.description',
        'resources.website',
        'resources.additional_info');

    $query->where(function($query) use ($searchTerms, $fields) {
        foreach ($searchTerms as $term)
        {
            foreach ($fields as $field)
            {
                $query->orWhere($field, 'LIKE', '%'. $term .'%');
            }
        }
    });
}

问题:假设我的表中有两个资源,一个带有 name foo,一个带有 name bar,一个带有 name foo bar。它们是按顺序创建并放入我的表中的。现在,如果我搜索“foo bar”,我得到的前两个结果将是fooand bar(因为它们在我的表中是第一个匹配 foo 或 bar),我的第三个结果将是foo bar. 如何进行此搜索,以便根据匹配的关键字数量对结果进行排序?所以foo bar将是第一个结果。

4

2 回答 2

1

您应该使用FULLTEXT搜索来实现这一点。您没有指定您正在使用哪个数据库引擎,所以我将给出一个 MySQL 示例。

首先,您需要对要搜索的字段启用全文索引。

ALTER TABLE resources ADD FULLTEXT search (name,description,website,additional_info);

然后,您需要在查询中得到类似以下内容:

SELECT
    *, MATCH(name,description,website,additional_info) AGAINST(SEARCH_TERMS) AS score
WHERE
    MATCH(name,description,website,additional_info) AGAINST(SEARCH_TERMS)

我会在 Laravel Query Builder 中使用类似这样的东西(未经测试):

if(Input::get('keyword'))
{
    $search = Input::get('keyword');
    $searchTerms = explode(' ', $search);

    $fields = array(
        '`resources.name`',
        '`resources.description`',
        '`resources.website`',
        '`resources.additional_info`'
    );

    $fields_str = implode(',', $fields);
    $query->whereRaw("match ($fields_str) against (? in boolean mode)")
    $query->addSelect(DB::raw("match ($fields_str) against (? in boolean mode)")
    // Need to bind twice because there are two question marks...
    $query->setBindings(array($searchTerms, $searchTerms))
}

根据您的搜索,您可能需要也可能不需要in boolean mode,或者您可能想要指定不同的模式。有关详细信息,请参阅 MySQL 手册。


注意:大多数关系数据库引擎并不擅长搜索。这不是他们最初设计的目的。如果你发现你的搜索需求比这个简单的例子更复杂,你应该考虑运行一个搜索服务器,比如 Lucene、Sphinx、Elasticsearch 或 Solr

(有关更多信息,请参阅http://blog.oneiroi.co.uk/mysql/php/mysql-full-text-search-with-percentage-scoring/http://www.mullie.eu/mysql-as -a-搜索引擎/ )

于 2014-10-13T17:51:34.767 回答
0

我最终使用以下解决方案进行搜索:

if(Input::get('keyword')) {
    $search = Input::get('keyword');
    $query->whereRaw("MATCH(resources.name, resources.description, resources.website, resources.additional_info) AGAINST(? IN BOOLEAN MODE)", 
        array($search)
    );
}

我通过阅读以下页面找到了这个解决方案:

如何按相关性对MYSQL全文搜索结果进行排序

http://creative-punch.net/2013/12/implementing-laravel-4-full-text-search/

我升级到 MySQL 5.6,所以我可以将全文索引添加到我的 InnoDB 表中。我必须按照我在语句MATCH中指定的顺序将全文索引添加到我想要运行的所有字段中。whereRaw

于 2014-10-14T15:55:15.933 回答