Разбор поисковых запросов в Java

Я пытался найти простой способ разобрать поисковый запрос и преобразовать его в SQL-запрос для моей БД.

Я нашел два решения:

  1. Lucene : мощная поисковая система на основе Java, содержащая анализатор запросов, но не очень настраиваемая, и я мог бы найти способ легко взломать / адаптировать ее для создания SQL-запросов.
  2. ANTLR : Ветеран текстового лексера-парсера. Используется для сборки чего угодно, от компиляторов до небоскребов. ANTLR легко настраивается, но теперь всем, кто коснется кода, придется выучить новый язык ...

Есть другие идеи?

Ответов (7)

SQL-ORM - это очень легкая библиотека Java, которая включает возможность создавать (динамический) SQL-запрос на Java в виде графа объектов.

IMHO, это гораздо лучший метод для построения динамических SQL-запросов, чем обычный метод конкатенации строк.

Отказ от ответственности: я внес очень незначительный вклад в этот проект.

String [] массив;

int checkWord(String searchWord)
{
    for(int i = 0; i < array.length; i++)
    {
        if(searchWord.equals(array[i]))
            return i;
    }
    return 0;

}

Во многом зависит от типа запросов, которые вам нужно проанализировать, и в некоторой степени от структуры данных в вашей базе данных. Я собираюсь предположить, что вы не пытаетесь выполнять полнотекстовый поиск в БД (то есть в поисковой системе по всей вашей БД), потому что, как скажет вам большинство специалистов по поиску информации, производительность для этого ужасна. Инвертированные индексы, безусловно, лучший способ сделать это.

Расскажите нам немного больше о реальной проблеме: что будут вводить пользователи, что они ожидают в результате и какова модель данных. Создайте поисковое решение без этой информации, и вы получите далеко не оптимальный результат.

Что именно вы имеете в виду? Я использовал Lucene для текстового поиска, но там, где он лучше всего, так это создание индекса и поиск по нему, а не обращение к базе данных.

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

Мне показалось бы, что преобразование поискового запроса в оператор SQL немного беспорядочно.

Кроме того, вот отличное начальное руководство, объясняющее базовую структуру Lucene .

Вы правильно предполагаете, что я не ищу полнотекстовый поиск. Информация выглядит примерно так, как эта схема для информации о книге: Имя: строка, издатель: строка, num_pages int, publish_date: date ...

Поисковые запросы имеют вид:

  1. Гарри Поттер (поиск по книгам, в названии которых есть и Гарри, и Поттер)
  2. издатель: Nature * pages> 100 (книги от издателя, начиная с Nature, более 100 книг)
  3. («Новый год» или Рождество) и подарок (вы понимаете ...)
  4. физика и публикации> 01.01.2008 (новые книги по физике)

Вы можете попробовать использовать что-то вроде javacc (компилятор компилятора Java) для реализации синтаксического анализатора или просто вручную проанализировать строку с помощью грубой силы. Каждый раз, встречая выражение, вы представляете его как объект. Затем вам просто нужно перевести дерево выражений в предложение where.

Например: «Гарри Поттер» становится

new AndExp(new FieldContainsExp("NAME", "Harry"), new FieldContainsExp("NAME", "Potter")

И "издатель: Nature * страницы> 100" становится

new AndExp(new FieldContainsExp("PUBLISHER", "Nature"), FieldGreaterThan("PAGES", 100))

Затем, когда они у вас есть, их довольно легко превратить в SQL:

FieldContainsExp.toSQL(StringBuffer sql, Collection<Object> args) {
  sql.append(fieldName);
  sql.append(" like ");
  sql.append("'%?%'");
  args.add(value);
}

AndExp.toSQL(StringBuffer sql, Collection<Object> args) {
    exp1.toSQL(sql, args);
    sql.append(" AND ");
    exp2.toSQL(sql, args);
}

Остальное вы можете себе представить. Вы можете вкладывать выражения And так глубоко, как хотите.

Попробуйте объединить инструмент ORM (например, openJPA) и Compass (фреймворк для OSEM). Он автоматически индексирует обновления, сделанные с помощью инструментов ORM, и дает вам возможности Lucene для поиска. После этого вы, конечно, можете получить объект из БД. Он превосходит любое поисковое решение на основе SQL.