Laravel упругого поиска не дает содержит или как матч
Я хотел, чтобы эластичный поиск был реализован для всех моих поисковых запросов laravel. У меня установлен новейший Laravel и новейший эластичный поиск с использованием brew.
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',
]
]
],
]
];
}
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
также.
1 ответ
Как я вижу, твой ref_num
поле имеет keyword
тип. Выполнение полнотекстовых запросов (например, match
или же match_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.
Если вы хотите достичь того же результата на text
введите поле вы должны правильно подготовить свой индекс. Например, вы можете использовать свой собственный анализатор с токенайзером NGram, который разбивает слова на токены n-граммы.
По умолчанию любой из анализаторов не разделяет слова, поэтому в вашем случае в индексе был только один токен:
POST /_analyze
{
"analyzer": "standard",
"text": "I50263"
}
Результат:
{
"tokens": [
{
"token": "i50263",
"start_offset": 0,
"end_offset": 6,
"type": "<ALPHANUM>",
"position": 0
}
]
}
Для полнотекстового поиска Elasticsearch базируется на токенах, которые он имеет в индексе. Если токены не совпадают с токенами из условия поиска, совпадение отсутствует.