我想为所有的Laravel搜索查询实现elasticsearch。我使用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"
}
我在这里使用driver 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',
]
]
],
]
];
}
SearchRule ,
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_num
为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
。
答案 0 :(得分:1)
如我所见,您的ref_num
字段是keyword
类型。执行full-text queries(例如match
或match_phrase
)不会给您任何结果。对于keyword
-s,您应该使用term level queries。也许prefix query在这里对您有所帮助。
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
,有关更多内容,您可以在documentation中阅读。
您可以使用bool query正确地将查询与其他任何字段上的其他查询一起使用。
如果您想在text
类型字段上获得相同的结果,则必须正确准备索引。例如,您可以将自定义分析器与NGram tokenizer一起使用,该分析器将单词分成n-gram标记。
默认情况下,任何分析器都不会拆分单词,因此在您的情况下,索引中只有一个令牌:
POST /_analyze
{
"analyzer": "standard",
"text": "I50263"
}
结果:
{
"tokens": [
{
"token": "i50263",
"start_offset": 0,
"end_offset": 6,
"type": "<ALPHANUM>",
"position": 0
}
]
}
对于全文搜索,Elasticsearch基于其在索引中的标记。如果令牌与搜索词中的令牌不匹配,则没有匹配项。