Сбой извлечения выражения на scala

Я пытаюсь извлечь последний набор чисел из таких выражений:

urn:fb:xyx:266730227 -> 266730227
urn:fb:pqr:(urn:fb:abc:6217401,10444030746) -> 10444030746

Этот код работает на Hive,

SELECT
CAST(regexp_extract(value.project, '.*,(\d+)', 1) AS BIGINT) AS p_id,
CAST(regexp_extract(value.context, '(\d+)', 0) AS BIGINT) AS co_id,
CAST(regexp_extract(key.identity, '(\d+)', 0) AS BIGINT) AS can_id
FROM some.dataset LIMIT 10

Однако в Spark scala возникает следующая ошибка:

FAILED, exitCode: 15, (reason: User class threw exception: scala.StringContext$InvalidEscapeException: invalid escape '\d' not one of [\b, \t, \n, \f, \r, \\, \", \'] at index 94 in "
|SELECT
|  *,
|  CAST(regexp_extract(value.project, '.*,(\d+)', 1) AS BIGINT) AS p_id,
|  CAST(regexp_extract(value.context, '(\d+)', 0) AS BIGINT) AS co_id,
|  CAST(regexp_extract(key.identity, '(\d+)', 0) AS BIGINT) AS ca_id
|FROM ". Use \\ for literal \.

Когда я пытаюсь сделать то, что рекомендует ошибка,

SELECT
CAST(regexp_extract(value.project, '.*,(\\d+)', 1) AS BIGINT) AS p_id,
CAST(regexp_extract(value.context, '(\\d+)', 0) AS BIGINT) AS co_id,
CAST(regexp_extract(key.identity, '(\\d+)', 0) AS BIGINT) AS can_id
FROM some.dataset LIMIT 10

Все столбцы результатов равны NULL.

'([[:digit:]]+)' работает?

Wiktor Stribiżew 21.12.2020 23:27
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
1
375
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Я также много раз ошибался в этом - в конце концов я просто отказался от использования обратной косой черты в своем регулярном выражении:

SELECT
CAST(regexp_extract(value.project, '.*,([0-9]+)', 1) AS BIGINT) AS p_id,
CAST(regexp_extract(value.context, '([0-9]+)', 0) AS BIGINT) AS co_id,
CAST(regexp_extract(key.identity, '([0-9]+)', 0) AS BIGINT) AS can_id
FROM some.dataset LIMIT 10

Это единственное, что сработало для меня. Отдых отличный, но только теория.

user11751463 23.12.2020 03:28

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

val df = Seq("urn:fb:xyx:266730227", "urn:fb:pqr:(urn:fb:abc:6217401,10444030746)").toDF("value")
df.createOrReplaceTempView("tbl")

// pattern as a regular string literal
df.withColumn("p_id", regexp_extract($"value", "(\\d+)", 1)).show(false)
+-------------------------------------------+---------+
|value                                      |p_id     |
+-------------------------------------------+---------+
|urn:fb:xyx:266730227                       |266730227|
|urn:fb:pqr:(urn:fb:abc:6217401,10444030746)|6217401  |
+-------------------------------------------+---------+

Вы можете пропустить это, используя необработанную строку или многострочную строку (как указано @mazaneicha) в шаблоне:

// pattern as a raw string, keep backslash as-is
df.withColumn("p_id", regexp_extract($"value", raw"(\d+)", 1)).show(false)
+-------------------------------------------+---------+
|value                                      |p_id     |
+-------------------------------------------+---------+
|urn:fb:xyx:266730227                       |266730227|
|urn:fb:pqr:(urn:fb:abc:6217401,10444030746)|6217401  |
+-------------------------------------------+---------+

// pattern as a multi-Line string where backslash is not escaped
df.withColumn("p_id", regexp_extract($"value", """(\d+)""", 1)).show(false)
+-------------------------------------------+---------+
|value                                      |p_id     |
+-------------------------------------------+---------+
|urn:fb:xyx:266730227                       |266730227|
|urn:fb:pqr:(urn:fb:abc:6217401,10444030746)|6217401  |
+-------------------------------------------+---------+

Когда обратная косая черта и regexp_extract (regexp_replace, split, str_to_map и т. д.) отображаются внутри выражения SQL (которое в основном является строкой), например expr(), df.selectExpr(), spark.sql(), df.filter(), df.where() и т. д., вам придется дважды экранировать обратную косую черту, например:

// regular string literals
spark.sql("select *, regexp_extract(value, '(\\\\d+)', 1) as p_id from tbl").show
// raw string to SQL expression
spark.sql(raw"select *, regexp_extract(value, '(\\d+)', 1) as p_id from tbl").show
// multi-Line string to SQL expression
spark.sql("""select *, regexp_extract(value, '(\\d+)', 1) as p_id from tbl""").show

df.withColumn("p_id", expr("regexp_extract(value, '(\\\\d+)', 1)")).show(false)
df.withColumn("p_id", expr(raw"regexp_extract(value, '(\\d+)', 1)")).show(false)
df.withColumn("p_id", expr("""regexp_extract(value, '(\\d+)', 1)""")).show(false)

df.filter("value rlike '\\\\d'").show
df.filter(raw"value rlike '\\d'").show
df.filter("""value rlike '\\d'""").show

Примечание. Нет синтаксиса для обработки необработанных или многострочных строк Scala внутри выражений SQL. Чтобы сделать то же самое, для spark 2.0+ вы можете установить spark.sql.parser.escapedStringLiterals=true (по умолчанию false, ссылка ), ниже по ссылке:

val ESCAPED_STRING_LITERALS = buildConf("spark.sql.parser.escapedStringLiterals") ..... .doc("При значении true строковые литералы (включая шаблоны регулярных выражений) остаются экранированными в нашем SQL" + "parser. По умолчанию установлено значение false, начиная с Spark 2.0. Установка значения true может восстановить поведение " + "до Spark 2.0") .версия("2.2.1") .booleanConf .createWithDefault (ложь)

Примеры:

spark.conf.set("spark.sql.parser.escapedStringLiterals", "true")

df.withColumn("p_id", expr("regexp_extract(value, '(\\d+)', 1)")).show(false)
df.withColumn("p_id", expr(raw"regexp_extract(value, '(\d+)', 1)")).show(false)
spark.sql("select *, regexp_extract(value, '(\\d+)', 1) as p_id from tbl").show
spark.sql("""select *, regexp_extract(value, '(\d+)', 1) as p_id from tbl""").show
df.filter(raw"value rlike '\d'").show

Боковое примечание: вышеприведенное обсуждение посвящено экранированию буквальных обратных косых черт внутри строк, если вам нужны фактические экранированные символы (например, новая строка \n, TAB \t, NUL char \0 или \u0000 и т. д.), то дополнительная обратная косая черта не требуется, например:

// merge multiple lines into one line
spark.sql("select *, regexp_replace(x,'\n+',',') as y from values ('1,2\n3\n\n4') as (x)").show
// split string into an array using NUL char or/and TAB
spark.sql("select *, split(x,'[\t\u0000]+') as y from values ('s\u0000x\ty\tz') as (x)").show

Другие вопросы по теме