0

我想为我所有的 laravel 搜索查询实现弹性搜索。我使用 brew 安装了最新的 Laravel 和最新的 elasticsearch。

curl http://localhost:9200/给,

{
  "name" : "_SFvSGk",
  "cluster_name" : "elasticsearch_an398690",
  "cluster_uuid" : "xBi3aTDaTkmA6dtzhpOrwg",
  "version" : {
    "number" : "6.5.4",
    "build_flavor" : "oss",
    "build_type" : "tar",
    "build_hash" : "d2ef93d",
    "build_date" : "2018-12-17T21:17:40.758843Z",
    "build_snapshot" : false,
    "lucene_version" : "7.5.0",
    "minimum_wire_compatibility_version" : "5.6.0",
    "minimum_index_compatibility_version" : "5.0.0"
  },
  "tagline" : "You Know, for Search"
}

在这里,我正在使用驱动程序 babenkoivan/scout-elasticsearch-driver

型号,

namespace App;

use ScoutElastic\Searchable;
use Illuminate\Database\Eloquent\Model;

class Customer extends Model
{
    use Searchable;

    /**
     * @var string
     */
    protected $indexConfigurator = CustomerIndexConfigurator::class;

    /**
     * @var array
     */
    protected $searchRules = [
        CustomerSearchRule::class
    ];

    /**
     * @var array
     */
    protected $mapping = [
        'properties' => [
            'text' => [
                'type' => 'text',
                'fields' => [
                    'ref_num' => [
                        'type' => 'keyword',
                    ]
                ]
            ],
        ]
    ];
}

搜索规则

namespace App;

use ScoutElastic\SearchRule;

class CustomerSearchRule extends SearchRule
{
    /**
     * @inheritdoc
     */
    public function buildHighlightPayload()
    {
        return [
            'fields' => [
                'ref_num' => [
                    'type' => 'plain'
                ]
            ]
        ];
    }

    /**
     * @inheritdoc
     */
    public function buildQueryPayload()
    {
        $query = $this->builder->query;

        return [
                [
                    'match' => [
                        'ref_num' => [
                            'query' => $query,
                            'boost' => 2
                        ]
                    ]
                ]
        ];
    }
}

配置器

namespace App;

use ScoutElastic\IndexConfigurator;
use ScoutElastic\Migratable;

class CustomerIndexConfigurator extends IndexConfigurator
{
    use Migratable;

    /**
     * @var array
     */
    protected $settings = [
        //
    ];
}

我有一个记录ref_numas I50263。所以当我搜索I50相同的时候我应该得到这个记录like query。我尝试了以下所有搜索,但我只得到了完整单词的结果I50263

return Customer::search('I50')->get();
// no record
return Customer::search('I50263')->get();
// got record
return Customer::searchRaw([
  'query' => [
     'bool' => [
        'must' => [
            'match' => [
                'ref_num' => 'I502'
            ]
        ]
     ]
  ]
]);
// no record
return Customer::searchRaw([
  'query' => [
      'bool' => [
          'must' => [
             "match_phrase" => [
                "ref_num" => [
                   "query" => "I50",
                   "boost" => 1
                 ]
              ]
           ]
        ]
     ]
 ]);
 // no record

也尝试过字段类型text

4

1 回答 1

1

如我所见,您的ref_num字段属于keyword类型。执行全文查询(如matchmatch_phrase)不会给您任何结果。对于keyword-s,您应该使用术语级别的查询。也许前缀查询在这里对您有所帮助。

例子

映射

PUT /so54176561
{
  "mappings": {
    "_doc": {
      "properties": {
        "ref_num": {
          "type": "text",
          "fields": {
            "raw": {
              "type": "keyword"
            }
          }
        }
      }
    }
  }
}

添加示例文档

POST /so54176561/_doc/1
{
  "ref_num": "I50263"
}

类型字段的全文match搜索text

按总价值

POST /so54176561/_search
{
  "query": {
    "match": {
      "ref_num": "I50263"
    }
  }
}

结果:找到文件

通过值的前缀

POST /so54176561/_search
{
  "query": {
    "match": {
      "ref_num": "I50"
    }
  }
}

结果:找不到文件

类型字段上的术语级别prefix搜索keyword

POST /so54176561/_search
{
  "query": {
    "prefix": {
      "ref_num.raw": "I50"
    }
  }
}

结果:找到文件

如您所见,在示例中我使用了这种子字段(raw是一个子字段,ref_num但具有不同的类型)。在 Elasticsearch 中调用它,您可以在文档fields中阅读更多相关信息。

您可以简单地将查询与任何其他使用bool 查询的字段上的任何其他查询一起使用。

如果您想在texttype 字段上获得相同的结果,则必须正确准备索引。例如,您可以将自定义分析器与NGram 标记器一起使用,它将单词拆分为 n-gram 标记。

默认情况下,任何分析器都不会拆分单词,因此在您的情况下,索引中只有一个标记:

POST /_analyze
{
  "analyzer": "standard",
  "text": "I50263"
}

结果:

{
  "tokens": [
    {
      "token": "i50263",
      "start_offset": 0,
      "end_offset": 6,
      "type": "<ALPHANUM>",
      "position": 0
    }
  ]
}

对于全文搜索,Elasticsearch 基于它在索引中的标记。如果标记与搜索词中的标记不匹配,则不匹配。

于 2019-01-14T11:35:24.150 回答