Elasticsearch 匹配 php 中的子字符串


Elasticsearch match substring in php

下面是我使用 elasticsearch 生成索引的代码。索引已成功生成。基本上,我正在使用它根据电影名称,演员姓名和Gener生成自动建议。

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

这仅匹配字符串中的特定单词。我想匹配包含多个单词的子字符串(即"tom kr"应该返回"tom kruz"(。

我发现很少的文档,说可以使用">ngram"。但我不知道,我应该如何在我的代码中实现它,因为我正在使用基于数组的 elasticsearch 配置,并且所有支持文档都提到了 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);
}

这里的问题在于Elasticsearch构建了一个倒排索引。假设您使用标准分析仪,句子"汤姆克鲁兹是顶级枪"被分成 6 个令牌:汤姆 - 克鲁兹 - 是 - 一个 - 顶级 - 枪。这些标记被分配给文档(有一些关于那里位置的元数据,但让我们暂时把它放在一边(。

如果要进行部分匹配,可以,但只能在单独的令牌上,而不是根据需要越过令牌边界。建议拆分搜索字符串并从这些字符串中构建通配符查询。

另一种选择确实是使用 ngram 或 edge_ngram 令牌过滤器。这将要做的(在索引时(是提前创建这些部分令牌(如 t - to - tom - ... - k - kr - kru - kruz - ...(,您只需在(匹配(搜索中输入"tom kr",它就会匹配。不过要小心:这会膨胀你的索引(如你所见,它将存储更多的代币(,你需要自定义分析器,并且可能需要相当多的关于你的映射的知识。

通常,(edge_(ngram 路由仅对自动完成之类的内容是一个好主意,而不适用于索引中的任何文本字段。有几种方法可以解决问题,但大多数方法都涉及构建单独的功能来检测拼写错误的单词并尝试为其建议正确的术语。

尝试创建此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
}