Searchkick не ищет несколько терминов при указании полей

Может ли кто-нибудь дать совет по следующему, пожалуйста?

Я использую searchkick/elasticsearch и хочу найти ключевой термин или термины в нескольких полях (имя, производитель). Так, например, если я ищу продукт под названием «мой продукт», созданный моим «каким-то производителем», я ожидаю, что этот результат появится, если я ищу «мой продукт», «какой-то производитель» или «мой продукт какой-то производитель», поскольку оба эти термина включены либо в полях имени или производителя.

Моя проблема заключается в следующем:

@products = Product.search query

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

@products = Product.search query, fields: [:name, :manufacturer_name]

Он вернет результат только для "myproduct" или "somecompany", но не "myproduct somecompany".

Теперь это не имеет большого значения, так как я могу полностью удалить опцию полей, НО мне нужно использовать searchkicks word_start для поля имени. Итак, мой последний запрос выглядит примерно так:

@products = Product.search query, fields: [{name: :word_start}, :manufacturer_name]

Я бы хотел, чтобы пользователи искали первую строку продукта и могли также вводить производителя, например, «myprod somecompany», к сожалению, это возвращает нулевые результаты, когда я надеялся, что он вернет продукт с именем myproduct, сделанный какой-то компанией.

Я пропустил что-то действительно очевидное здесь? я могу изменить добавить

operator: 'or'

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

вот мой код модели также

class Product < ActiveRecord::Base
 searchkick word_start: [:name]
end

Спасибо


person drac    schedule 23.09.2015    source источник
comment
У меня точно такая же проблема, ты разобрался?   -  person William Weckl    schedule 11.12.2015
comment
Разобрался, написал как ответ.   -  person William Weckl    schedule 14.12.2015


Ответы (2)


Если все ваши поля используют один и тот же анализатор, вы можете использовать elasticsearch функцию под названием cross_fields. Если это не так, вы можете использовать query_string. К сожалению, searchkick пока не поддерживает cross_fields и query_string. Итак, вы должны сделать это самостоятельно.

Индекс (разные анализаторы)

searchkick merge_mappings: true, mappings: {
  product: {
    properties: {
      name: {
        type: 'string',
        analyzer: 'searchkick_word_start_index',
        copy_to: 'grouped'
      },
      manufacturer_name: {
        type: 'string',
        analyzer: 'default_index',
        copy_to: 'grouped'
      },
      grouped: {
        raw: {type: 'string', index: 'not_analyzed'}
      }
    }
  }
}

Поиск с помощью cross_fields

@products = Product.search(body: {
  query: {
     multi_match: {
                  query: query,
                  type: "cross_fields",
                  operator: "and",
                  fields: [
                      "name",
                      "manufacturer_name",
                      "grouped",
                  ]
              }
         }
}

Поиск с помощью query_string

@products = Product.search(body: {
  query: {
      query_string: {
                  query: query,
                  default_operator: "AND",
                  fields: [
                      "name",
                      "manufacturer_name",
                      "grouped",
                  ]
              }
         }
}

Обновление. Мой ответ изменен на использование различных анализаторов и нескольких полей в соответствии с этим решением.

К сожалению, передавая запрос elasticsearch самостоятельно, вы теряете searchkick функции, такие как выделение и конверсии, но вы все равно можете это сделать, добавив его в запрос elasticsearch.

Добавление выделения в запрос

@products = Product.search(body: {
  query: {
    ...
  }, highlight: {
    fields: {
      name: {},
      manufacturer_name: {}
    }
  }

Добавление конверсий в запрос

@products = Product.search(body: {
  query: {
    bool: {
      must: {
        dis_max: {
          queries: {
            query_string: {
              ...
            }
          }
        }
      },
      should: {
        nested: {
          path: 'conversions',
          score_mode: 'sum',
          query: {
            function_score: {
              boost_mode: 'replace',
              query: {
                match: {
                  "conversions.query": query
                }
              },
              field_value_factor: {
                field: 'conversions.count'
              }
            }
          }
        }
      }
    }
  }
person William Weckl    schedule 14.12.2015
comment
откуда вы взяли 'searchkick_word_start_index' и 'default_index'??? - person Deez Nuuts; 28.06.2019

Самый простой способ сделать это — объединить поля в одно методом search_data.

class Product
  def search_data
    {
      full_name: "#{manufacturer_name} #{name}"
    }
  end
end

Не забудьте потом переиндексировать. Затем используйте полное имя для поиска. Все функции Searchkick продолжат работать.

person Andrew Kane    schedule 10.08.2018