Эластичный поиск нечеткого соответствия с отображением точных совпадений первым

#php #elasticsearch #fuzzy-search

#php #elasticsearch #нечеткий поиск

Вопрос:

Я хочу использовать нечеткое сопоставление в запросе, но с точными совпадениями, отображаемыми в верхней части результатов.

Я пробовал следующее.

 $return = $this->_client->search(
            array(
                'index' => self::INDEX,
                'type'  => self::TYPE,
                'body'  => array(
                    'query' => array(
                        'bool' => array(
                            'must' => array(
                                'multi_match' => array(
                                    'query'     => $query,
                                    'fields'    => array('name', 'brand', 'description'),
                                    'boost'     => 10,
                                ),
                                'fuzzy_like_this' => array(
                                    'like_text' => $query,
                                    'fields'    => array('name', 'brand', 'description'),
                                    'fuzziness' => 1,
                                ),
                            ),
                        ),
                    ),
                    'size' => '5000',
                ),
            )
        );
  

Это не работает из-за ошибки неправильного запроса.

Есть идеи?

Комментарии:

1. Теперь я понимаю, чего вы хотите :). Вы пробовали sense или инструмент, позволяющий написать запрос, который вам нравится, в чистом json? Я обнаружил, что это намного проще, если сначала заставить его работать непосредственно с elasticsearch с помощью sense, а затем перевести его в NEST (который я использую в .NET).

2. Нет, пока нет. Я пойду посмотрю на sense. Это раздражает, я бы подумал, что точные совпадения действительно окажутся на вершине по умолчанию.

3. Я думаю, что ваш запрос кажется немного странным. Когда я читаю это, кажется, что у вас должно быть совпадение с несколькими совпадениями и fuzzy_like_this, это должно быть should. Смотрите мой ответ.

Ответ №1:

В итоге я не использовал нечеткое сопоставление для решения своей проблемы и пошел с использованием ngram.

 /**
 * Map - Create a new index with property mapping
 */
public function map()
{
    $params['index'] = self::INDEX;

    $params['body']['settings'] = array(
        'index' => array(
            'analysis' => array(
                'analyzer' => array(
                    'product_analyzer' => array(
                        'type'      => 'custom',
                        'tokenizer' => 'whitespace',
                        'filter'    => array('lowercase', 'product_ngram'),
                    ),
                ),
                'filter' =>  array(
                    'product_ngram' => array(
                        'type' => 'nGram',
                        'min_gram' => 3,
                        'max_gram' => 5,
                    ),
                )
            ),

        )
    );

    //all the beans
    $mapping = array(
        '_source'    => array(
            'enabled' => true
        ),
        'properties' => array(
            'id'          => array(
                'type' => 'string',
            ),
            'name'        => array(
                'type'     => 'string',
                'analyzer' => 'product_analyzer',
                'boost'    => '10',
            ),
            'brand'       => array(
                'type' => 'string',
                'analyzer' => 'product_analyzer',
                'boost'    => '5',
            ),
            'description' => array(
                'type' => 'string',
            ),
            'barcodes'    => array(
                'type' => 'string'
            ),
        ),
    );

    $params['body']['mappings'][self::TYPE] = $mapping;

    $this->_client->indices()->create($params);
}


public function search($query)
{
    $return = $this->_client->search(
        array(
            'index' => self::INDEX,
            'type'  => self::TYPE,
            'body'  => array(
                'query' => array(
                    'multi_match' => array(
                        'query'  => $query,
                        'fields' => array('id', 'name', 'brand', 'description', 'barcodes'),
                    ),
                ),
                'size' => '5000',
            ),
        )
    );

    $productIds = array();

    if (!empty($return['hits']['hits'])) {
        foreach ($return['hits']['hits'] as $hit) {
            $productIds[] = $hit['_id'];
        }
    }

    return $productIds;
}
  

Результат — это именно то, что я искал. Он создает совпадения на основе того, сколько частей ngram содержит в себе поисковый запрос.

Комментарии:

1. классная штука, я думаю, что это может быть лучшим подходом, чем нечеткий, поэтому спасибо, что поделились.

Ответ №2:

Отказ от ответственности, я не специалист по php, но у меня есть некоторые проблемы с вашим запросом:

 $return = $this->_client->search(
    array(
        'index' => self::INDEX,
        'type'  => self::TYPE,
        'body'  => array(
            'query' => array(
                'bool' => array(
                    'should' => array(
                        array(
                            'multi_match' => array(
                                'query'     => $query,
                                'fields'    => array('name', 'brand', 'description'),
                                'boost'     => 10,
                            ),
                        ),
                        array(
                            'fuzzy_like_this' => array(
                                'like_text' => $query,
                                'fields'    => array('name', 'brand', 'description'),
                                'fuzziness' => 1,
                            ),
                        ),
                    ),
                ),
            ),
            'size' => '5000',
        ),
    )
);
  

Изменение на должно сделать так, чтобы совпадал только один из запросов, а не оба. Вы можете прочитать о запросе bool здесь:http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html

Комментарии:

1. Спасибо, я все еще получаю ошибку » QueryParsingException [[products] [_na] запрос неверно сформирован, нет поля после start_object]; }]», «статус»: 400}». Ошибка.