Как наиболее эффективно создать поисковый фильтр как для отдельных, так и для сложных терминов? - PullRequest
2 голосов
/ 16 мая 2019

У нас есть ситуация, когда мы выполняем поиск, и пользователь может предоставить список элементов в качестве фильтра для поиска.

Например, допустим, мы искали рецепты, в которых были конкретные продукты. У нас может быть список возможных продуктов, например:

  • говядина
  • курица
  • рыба
  • морковь
  • горох
  • лук
  • рис
  • бобы

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

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

(я создаю этот пример, основываясь на наших реальных бизнес-требованиях, которые гораздо скучнее, но по сути это идея.)

Существует несколько возможных решений, которые могут быть оттенками одного и того же:

  • Имейте два разных списка в критериях поиска, один для перечисления отдельные элементы и один для перечисления групп, а затем объединить два при фильтрации запросов.
  • иметь один список в критериях поиска с перечислением, которое включает как отдельные предметы, так и группы предметов.

Но я чувствую, что мне не хватает решения, которое могло бы быть немного более элегантным в представлении групповых / индивидуальных отношений. Есть шаблон, который обращается к этой ситуации?

(PS: это на Java, но я не думаю, что это особенно важно.)

Ответы [ 2 ]

1 голос
/ 04 июня 2019

Для максимальной гибкости вы можете применить Составной шаблон проектирования .Это позволяет обрабатывать составной запрос (например, «любое мясо») так же, как любой другой запрос.В вашем случае имеет смысл использовать перечисление для листа.

Сначала вам нужен родительский тип интерфейса.В этом случае мы можем включить метод, который возвращает все отдельные термины в запросе.

public interface Query {    
    EnumSet<Term> getTerms();
}

Затем для отдельных терминов используйте перечисление, которое возвращает себя в качестве «списка» терминов:

public enum Term implements Query {
    BEEF, CHICKEN, FISH, CARROTS, PEAS, ONIONS, RICE, BEANS;

    @Override
    public EnumSet<Term> getTerms() {
        return EnumSet.of(this);
    }
}

Для групп терминов вы используете составной класс:

public class CompositeQuery implements Query {

    private final List<Query> queries;

    public CompositeQuery( Query... queries ) {
        this.queries = Arrays.asList(queries);
    }

    @Override
    public EnumSet<Term> getTerms() {
        Set<Term> result = new HashSet<>();
        for( Query query : queries ) {
            result.addAll(query.getTerms());
        }
        return EnumSet.copyOf(result);
    }
}

А для групп по умолчанию вы можете определить константы (я бы объявил их в интерфейсе Query):

Query MEAT = new CompositeQuery(Term.BEEF, Term.CHICKEN);
Query VEGETABLES = new CompositeQuery(Term.CARROTS, Term.ONIONS, Term.PEAS);

Composite даже позволяет вам иметь группы групп:

Query MEAT_VEGETABLES = new CompositeQuery( MEAT, VEGETABLES );
1 голос
/ 16 мая 2019

Когда дело доходит до поиска, Apache SOLR и Elastic Search являются лучшими. Вы можете делать все типы группировки, категоризации и других типов поиска в упомянутой структуре. Я предложу использовать поиск Apache Solr или Elastic вместо написания кода с нуля.

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