Elasticsearch匹配php

时间:2016-02-05 06:43:15

标签: php elasticsearch elastica

下面给出了我使用elasticsearch.Index生成索引的代码成功生成。基本上我用它来生成autosuggest,具体取决于电影名称,演员名称和gener。

现在我的要求是,我需要将子字符串与特定字段匹配。如果我使用$params['body']['query']['wildcard']['field'] = '*sub_word*';,这工作正常。(即搜索'to'给'tom kruz'但搜索'tom kr'返回没有结果)。

这只匹配string中的特定单词。我想匹配包含多个单词的子串(即'tom kr'应该返回'tom kruz')。

我发现很少有文档,说可以使用' ngram '。 但我不知道,我应该如何在我的代码中实现它,因为我正在使用基于数组的弹性搜索配置,所有支持文档都提到了json fromat中的配置。

请帮忙。

require 'vendor/autoload.php';

$client = \Elasticsearch\ClientBuilder::create()
->setHosts(['http://localhost:9200'])->build();

/*************Index a document****************/
$params = ['body' => []];
$j = 1;
for ($i = 1; $i <= 100; $i++) {
    $params['body'][] = [
        'index' => [
            '_index' => 'pvrmod',
            '_type' => 'movie',
            '_id' => $i
        ]
    ];
    if ($i % 10 == 0) 
        $j++;
    $params['body'][] = [
        'title' => 'salaman khaan'.$j,
        'desc' => 'salaman khaan description'.$j,
        'gener' => 'movie gener'.$j,
        'language' => 'movie language'.$j,
        'year' => 'movie year'.$j,
        'actor' => 'movie actor'.$j,
    ];

    // Every 10 documents stop and send the bulk request
    if ($i % 10 == 0) {
        $responses = $client->bulk($params);

        // erase the old bulk request
        $params = ['body' => []];

        unset($responses);
    }
}

// Send the last batch if it exists
if (!empty($params['body'])) {
    $responses = $client->bulk($params);
}

2 个答案:

答案 0 :(得分:6)

这里的问题在于Elasticsearch构建了倒排索引。假设你使用标准分析仪,句子“汤姆克鲁兹是一把顶级枪”得到的分为6个令牌:汤姆 - 克鲁兹 - 是 - 顶级枪。这些令牌被分配到文档中(包含有关位置的一些元数据,但是暂时让它留在一边)。

如果你想进行部分匹配,你可以,但只能在单独的标记上,而不是你想要的标记边界。从这些字符串中拆分搜索字符串和构建通配符查询的建议是一种选择。

另一种选择确实是使用ngramedge_ngram令牌过滤器。那会做什么(在索引时)是提前创建那些部分标记(比如t - to - tom - ... - k - kr - kru - kruz - ...)你可以放入'tom kr'在你的(匹配)搜索中它会匹配。但要小心:这会使你的索引膨胀(你可以看到,它会存储更多的标记),你需要custom analysers并且可能对你的映射有很多了解。

通常,(edge_)ngram路由仅适用于自动完成等操作,不适用于索引中的任何文本字段。有几种方法可以解决您的问题,但大多数方法涉及构建单独的功能来检测拼写错误的单词并尝试为其提出正确的条款。

答案 1 :(得分:5)

尝试创建此JSON

{
"query": {
    "filtered": {
        "query": {
            "bool": {
                "should": [
                    {
                        "wildcard": {
                            "field": {
                                "value": "tom*",
                                "boost": 1
                            }
                        }
                    },
                    {
                        "field": {
                            "brandname": {
                                "value": "kr*",
                                "boost": 1
                            }
                        }
                    },
                ]
            }
        }
    }
}

您可以展开搜索字词

$searchTerms = explode(' ', 'tom kruz');

然后为每个

创建通配符
foreach($searchTerms as $searchTerm) {
//create the new array
}