Я пытаюсь извлечь последний набор чисел из таких выражений:
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.
Я также много раз ошибался в этом - в конце концов я просто отказался от использования обратной косой черты в своем регулярном выражении:
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
Это единственное, что сработало для меня. Отдых отличный, но только теория.
Все дело в том, как экранировать символы внутри строковых литералов. По умолчанию строковые литералы (включая шаблоны регулярных выражений) не экранируются, и вам придется использовать обратную косую черту, чтобы вручную экранировать литеральные обратные косые черты. например:
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
'([[:digit:]]+)'
работает?