【问题标题】:Elasticsearch match substring in phpphp中的Elasticsearch匹配子字符串
【发布时间】:2016-05-15 01:22:36
【问题描述】:

下面给出的是我使用 elasticsearch 生成索引的代码。索引生成成功。基本上我使用它来根据电影名称、演员名称和类型生成自动建议。

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

这仅匹配字符串中的特定单词。我想匹配包含多个单词的子字符串(即'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);
}

【问题讨论】:

    标签: php elasticsearch elastica


    【解决方案1】:

    这里的问题在于 Elasticsearch 构建了倒排索引。假设您使用标准分析器,句子“tom kruz is a top gun”会分成 6 个标记:tom - kruz - is - a - top - gun。这些标记被分配给文档(有一些关于那里的位置的元数据,但我们暂时把它放在一边)。

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

    另一个选项确实是使用ngramedge_ngram 令牌过滤器。这样做(在索引时)是提前创建那些部分标记(如 t - to - tom - ... - k - kr - kru - kruz - ...),您只需输入 'tom kr'在您的(匹配)搜索中,它会匹配。不过要小心:这会使您的索引膨胀(如您所见,它将存储更多令牌),您需要 custom analysers 并且可能需要对您的映射有相当多的了解。

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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 亲爱的 costa,谢谢您的回答。但只是一个查询,您确定,对单个单词运行通配符搜索会给我匹配多字子字符串的最相关结果吗?
      猜你喜欢
      • 1970-01-01
      • 2014-06-08
      • 1970-01-01
      • 1970-01-01
      • 2018-08-03
      • 2022-01-19
      • 2021-08-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多