Laravel упругого поиска не дает содержит или как матч - PullRequest
0 голосов
/ 14 января 2019

Я хотел, чтобы эластичный поиск был реализован для всех моих поисковых запросов 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 Ответ

0 голосов
/ 14 января 2019

Как я вижу, ваше поле ref_num имеет тип keyword. Выполнение полнотекстовых запросов (например, match или match_phrase) не даст вам никаких результатов. Для keyword -s вы должны использовать запросы уровня термина . Возможно, префикс запроса будет полезен для вас здесь.

Пример

Mapping

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 query .

Если вы хотите достичь того же результата в поле типа text, вы должны правильно подготовить свой индекс. Например, вы можете использовать свой собственный анализатор с токенайзером NGram , который разбивает слова на токены n-граммы.

По умолчанию любой из анализаторов не разделяет слова, поэтому в вашем случае в индексе был только один токен:

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

Результат:

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

Для полнотекстового поиска Elasticsearch базируется на токенах, которые есть в индексе. Если токены не совпадают с токенами из условия поиска, совпадение отсутствует.

...