В этой статье мы расскажем о регулярных выражениях и о том, как их использовать в Manticore Search
Если говорить о поиске текста, самый простой способ — сравнение строк: поисковая строка и документ или поле должны полностью совпадать. Следующий способ — простое сопоставление с шаблоном, при котором поисковая строка может совпасть с частью поля. В таком сопоставлении можно использовать базовые операторы, например подстановочные знаки, где метасимвол * или % означает «любые символы». В базах данных для этого обычно используют оператор SQL LIKE, например:
SELECT * FROM mytable WHERE title LIKE '%and%'
найдёт строки, в заголовках которых буквально встречается подстрока «and».
Регулярные выражения работают с обычным текстом, как и LIKE, но они предоставляют мощный набор метасимволов-операторов, позволяющих создавать сложные шаблоны сопоставления. Шаблон regex работает на уровне символов и может сопоставлять буквы, цифры и другие символы, либо по буквальному значению (например, /abc/ будет соответствовать abc), либо по типу класса, например \w будет соответствовать [A-Za-z0-9_]. Шаблон также может включать логическое or, как abc|xyz, квантификаторы — ? означает ноль или одно вхождение предшествующего символа или подстановочного знака (метасимвол .).
В отличие от regex, полнотекстовый поиск не работает с обычным текстом, а разбирает тексты и сегментирует их на слова. Полнотекстовый поиск не пытается найти шаблон в строке, а ищет в наборе слов. Хотя регулярные выражения могут находить и выделять слова, у них есть естественные ограничения: они не позволяют легко выполнять булевы поиски вроде abc -xyz или работать с морфологией. Некоторые возможности, присутствующие в регулярных выражениях, также доступны в полнотекстовом поиске, например операторы start/end. Некоторые работают иначе. Например, подстановочные знаки в regex могут заменять любое количество символов, но в полнотекстовом поиске подстановочные знаки могут расширяться только в пределах слова или полностью заменять слово.
Как используются регулярные выражения в Manticore Search?
Регулярные выражения были доступны до настоящего времени как опциональная функция на этапе индексации через regexp_filter
. Regex можно использовать для преобразования строк, что иначе было бы сложнее реализовать обычными опциями токенизации. Например, лигатуру 'ae' можно заменить на 'a' или заменить шаблон вроде XX" на XX inch.
Начиная с версии 2.7.5 регулярные выражения можно использовать в SELECT-запросах с помощью функции REGEX() . REGEX() принимает на вход строку, которая может быть получена из строкового атрибута или свойства JSON, а также регулярное выражение, которое будет проверено на входных данных. REGEX работает только со значениями атрибутов, её нельзя использовать для полнотекстовых полей.
Зачем нужна SQL-функция REGEX, если мы уже можем индексировать тексты в полнотекстовых полях?
Во-первых, у нас могут быть строки (либо как атрибуты, либо в JSON-данных), к которым необходимо применить поисковый шаблон, не связанный напрямую с полнотекстовым сопоставлением. Например, метаданные могут содержать некоторые коды, и мы хотим сузить поиск, оставив только записи, где эти коды начинаются с цифры, например
SELECT * FROM myindex WHERE MATCH('something') AND REGEX(json_attr.code, "^\d\w+")
Ещё одна причина — в настоящее время текстовые данные из JSON-атрибутов не индексируются как полнотекстовые. Если нам нужно выполнить над некоторыми строковыми свойствами более сложное сопоставление, чем простое сравнение, нам придётся перенести их в полнотекстовое поле (и использовать ZONEs для ограничения сопоставления определёнными метками) или в несколько полнотекстовых полей (что может стать проблемой, если количество таких свойств варьируется).
Например, метаданные продукта, заключённые в объект JSON, могут содержать свойство со списком совместимых устройств этого продукта. С помощью REGEX мы можем создать шаблон, который будет находить нужный нам продукт или даже серию этого продукта:
SELECT * FROM myindex WHERE MATCH('red case') AND REGEX(json_attr.compatible_devices, "Galaxy S[789]")
В некоторых случаях REGEX() может быть незаменима. Дайте нам знать, если вы сочтёте её полезной!
