정규 표현식 문법
정규 표현식 문법 (Regular expression syntax)
정규 표현식(regex)은 특수 기호와 연산자를 사용해 검색 패턴을 정의하는 방법이에요. 이러한 패턴을 사용하면 문자열에서 문자 시퀀스를 일치시킬 수 있습니다.
OpenSearch에서는 다음 쿼리 유형에서 정규 표현식을 사용할 수 있어요.
- regexp
- query_string
OpenSearch는 고유한 문법과 제한 사항을 가진 Apache Lucene regex 엔진을 사용해요. Perl 호환 정규 표현식(PCRE)을 사용하지 않으므로, 익숙한 일부 regex 기능이 다르게 동작하거나 지원되지 않을 수 있습니다.
출처: 문서
본문
regexp 쿼리와 query_string 쿼리 선택하기
regexp 쿼리와 query_string 쿼리 모두 정규 표현식을 지원하지만, 동작 방식이 다르고 활용 사례도 달라요.
- 패턴 매칭: regexp 쿼리는 정규식 패턴이 필드 값 전체와 일치해야 해요. query_string 쿼리는 정규식 패턴이 필드의 어떤 부분이든 일치할 수 있어요.
- flags 지원: regexp 쿼리는 flags가 선택적 regex 연산자를 지원해요. query_string 쿼리는 flags를 지원하지 않아요.
- 쿼리 유형: regexp 쿼리는 용어 레벨 쿼리(점수 계산 없음)이고, query_string 쿼리는 전체 텍스트 쿼리(점수 계산 및 파싱됨)예요.
- 사용 사례: regexp 쿼리는 keyword 또는 정확한 필드에 대한 엄격한 패턴 매칭에 가장 적합하고, query_string 쿼리는 regex 패턴을 지원하는 유연한 쿼리 문자열을 사용해 분석된 필드 안에서 검색하는 데 가장 적합해요.
- 복잡한 쿼리 구성: regexp 쿼리는 regex 패턴으로 제한되고, query_string 쿼리는 AND, OR, 와일드카드, 필드, boost 및 기타 기능을 지원해요(Query string query 참고).
예약 문자 (Reserved characters)
Lucene의 regex 엔진은 모든 유니코드 문자를 지원해요. 하지만 다음 문자는 특수 연산자로 처리됩니다.
. ? + * | { } [ ] ( ) " \
활성화된 flags에 따라 선택적 연산자를 지정하는 다음 문자들도 예약될 수 있어요.
@ & ~
이 문자들을 문자 그대로 매치하려면 백슬래시(\)로 이스케이프하거나 전체 문자열을 큰따옴표로 감싸면 돼요.
\&: 리터럴&를 매치해요.\\: 리터럴 백슬래시(\)를 매치해요."hello@world": 전체 문자열 hello@world를 매치해요.
표준 regex 연산자 (Standard regex operators)
Lucene은 핵심 regex 연산자 세트를 지원해요.
.– 임의의 단일 문자를 매치해요. 예:f.n은 f 다음에 임의의 문자와 n이 오는 문자열(fan, fin 등)을 매치해요.?– 앞 문자가 0개 또는 1개인 것을 매치해요. 예:colou?r은 color와 colour를 매치해요.+– 앞 문자가 하나 이상인 것을 매치해요. 예:go+는 g 다음에 하나 이상의 o가 오는 문자열(go, goo, gooo 등)을 매치해요.*– 앞 문자가 0개 이상인 것을 매치해요. 예:lo*se는 l 다음에 0개 이상의 o와 se가 오는 문자열(lse, lose, loose, loooose 등)을 매치해요.{min,max}– 특정 반복 범위를 매치해요. max를 생략하면 매치되는 문자의 수에 상한이 없어요. 예:x{3}은 정확히 3개의 x(xxx)를 매치하고,x{2,4}는 2~4개의 x(xx, xxx, xxxx)를 매치하며,x{3,}는 3개 이상의 x(xxx, xxxx, xxxxx 등)를 매치해요.|– 논리 OR 역할을 해요. 예:apple|orange는 apple 또는 orange를 매치해요.( )– 문자를 하위 패턴으로 그룹화해요. 예:ab(cd)?는 ab와 abcd를 매치해요.[ ]– 세트나 범위에서 한 문자를 매치해요. 예:[aeiou]는 임의의 모음을 매치해요.-– 대괄호 안에 제공되면 범위를 나타내요(이스케이프되거나 대괄호의 첫 번째 문자인 경우 제외). 예:[a-z]는 임의의 소문자를 매치하고,[-az]는 -, a 또는 z를 매치하며,[a\-z]는 a, - 또는 z를 매치해요.^– 대괄호 안에 제공되면 논리 NOT 역할을 하며 문자 범위나 세트의 임의의 문자를 부정해요. 예:[^az]는 a 또는 z를 제외한 임의의 문자를 매치하고,[^a-z]는 소문자를 제외한 임의의 문자를 매치하며,[^-az]는 -, a, z를 제외한 임의의 문자를 매치하고,[^a\-z]는 a, -, z를 제외한 임의의 문자를 매치해요.
선택적 연산자 (Optional operators)
flags 파라미터를 사용해 추가 regex 연산자를 활성화할 수 있어요. 여러 flags는 |로 구분해요.
다음은 사용 가능한 flags예요.
- ALL (기본값) – 모든 선택적 연산자를 활성화해요.
- COMPLEMENT –
~를 활성화하며, 이는 바로 다음의 가장 짧은 표현식을 부정해요. 예:d~ef는 dgf, dxf를 매치하지만 def는 매치하지 않아요. - INTERSECTION –
&를 AND 논리 연산자로 활성화해요. 예:ab.+&.+cd는 시작 부분에 ab가 있고 끝 부분에 cd가 있는 문자열을 매치해요. - INTERVAL – 숫자 범위를 매치하는
<min-max>문법을 활성화해요. 예:id<10-12>는 id10, id11, id12를 매치해요. - ANYSTRING –
@가 임의의 문자열을 매치하도록 활성화해요.~와&와 결합해 제외 조건을 만들 수 있어요. 예:@&.*error.*&.*[0-9]{3}.*는 "error"라는 단어와 세 자리 숫자 시퀀스를 모두 포함하는 문자열을 매치해요.
지원되지 않는 기능 (Unsupported features)
Lucene의 엔진은 다음 자주 사용되는 regex 앵커를 지원하지 않아요.
^– 줄의 시작$– 줄의 끝
대신 패턴이 매치를 내기 위해 전체 문자열과 일치해야 해요.
예제 (Example)
정규 표현식을 시험해 보려면 다음 문서를 logs 인덱스에 인덱싱하세요.
PUT /logs/_doc/1
{
"message": "error404"
}
PUT /logs/_doc/2
{
"message": "error500"
}
PUT /logs/_doc/3
{
"message": "error1a"
}
예제: 정규 표현식을 포함하는 기본 쿼리
다음 regexp 쿼리는 message 필드의 전체 값이 "error" 뒤에 하나 이상의 숫자가 오는 패턴과 일치하는 문서를 반환해요. 값이 패턴을 부분 문자열로만 포함하고 있으면 일치하지 않습니다.
GET /logs/_search
{
"query": {
"regexp": {
"message": {
"value": "error[0-9]+"
}
}
}
}
이 쿼리는 error404와 error500을 매치해요.
{
"took": 28,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 1,
"hits": [
{
"_index": "logs",
"_id": "1",
"_score": 1,
"_source": {
"message": "error404"
}
},
{
"_index": "logs",
"_id": "2",
"_score": 1,
"_source": {
"message": "error500"
}
}
]
}
}
예제: 선택적 연산자 사용하기
다음 쿼리는 message 필드가 "error"로 시작하고 그 뒤에 400에서 500 사이의 숫자(포함)가 오는 문자열과 정확히 일치하는 문서를 매치해요. INTERVAL flag는 숫자 범위에 <min-max> 문법을 사용할 수 있게 해줘요.
GET /logs/_search
{
"query": {
"regexp": {
"message": {
"value": "error",
"flags": "INTERVAL"
}
}
}
}
이 쿼리는 error404와 error500을 매치해요.
{
"took": 22,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 1,
"hits": [
{
"_index": "logs",
"_id": "1",
"_score": 1,
"_source": {
"message": "error404"
}
},
{
"_index": "logs",
"_id": "2",
"_score": 1,
"_source": {
"message": "error500"
}
}
]
}
}
예제: ANYSTRING 사용하기
ANYSTRING flag가 활성화되면 @ 연산자는 전체 문자열을 매치해요. 이는 교집합(&)과 결합할 때 유용한데, 특정 조건에서 전체 문자열을 매치하는 쿼리를 구성할 수 있게 해주기 때문이에요.
다음 쿼리는 "error"라는 단어와 세 자리 숫자 시퀀스를 모두 포함하는 메시지를 매치해요. ANYSTRING을 사용해 전체 필드가 두 패턴의 교집합과 일치해야 한다고 주장해 보죠.
GET /logs/_search
{
"query": {
"regexp": {
"message.keyword": {
"value": "@&.*error.*&.*[0-9]{3}.*",
"flags": "ANYSTRING|INTERSECTION"
}
}
}
}
이 쿼리는 error404와 error500을 매치해요.
{
"took": 20,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 1,
"hits": [
{
"_index": "logs",
"_id": "1",
"_score": 1,
"_source": {
"message": "error404"
}
},
{
"_index": "logs",
"_id": "2",
"_score": 1,
"_source": {
"message": "error500"
}
}
]
}
}
이 쿼리는 xerror500, error500x, errorxx500도 매치한다는 점에 주의하세요.