Spark — извлечение числовых значений из буквенно-цифровой строки с помощью регулярного выражения

#regex #scala #apache-spark #apache-spark-sql #pyspark-sql

#регулярное выражение #scala #apache-spark #apache-spark-sql

Вопрос:

У меня есть буквенно-цифровой столбец с именем «Результат», который я хотел бы разобрать на 4 разных столбца: префикс, суффикс, значение и pure_text.

Я хотел бы решить это с помощью Spark SQL, используя RLIKE и REGEX, но также открытый для PySpark / Scala

pure_text: содержит только алфавиты (или) если присутствуют числа, то они должны содержать либо специальный символ «-«, либо несколько десятичных знаков (например, 9.9.0), либо число, за которым следует алфавит, а затем снова число (например, 3x4u)

префикс: все, что не может быть отнесено к категории «pure_text», будет принято во внимание. необходимо извлечь любые символы перед 1-й цифрой [0-9].

суффикс: все, что не может быть отнесено к категории «pure_text», будет принято во внимание. необходимо извлечь любые символы после последней цифры [0-9].

значение: все, что не может быть отнесено к категории «pure_text», будет принято во внимание. извлеките все числовые значения, включая десятичную точку.

 Result 

11 H
111L
<.004
>= 0.78
val<=0.6
xyz 100 abc
1-9
aaa 100.3.4 
a1q1
  

Ожидаемый результат:

 Result         Prefix     Suffix   Value    Pure_Text

11 H                           H      11
111L                           L     111       
.9                                   0.9
<.004               <              0.004
>= 0.78            >=               0.78
val<=0.6        val<=                0.6
xyz 100 abc      xyz         abc     100
1-9                                              1-9
aaa 100.3.4                              aaa 100.3.4 
a1q1                                            a1q1
  

Ответ №1:

Вот один из подходов с использованием UDF, который применяет сопоставление с шаблоном для извлечения содержимого строки в класс case. Сопоставление шаблона сосредотачивается вокруг числового value шаблона с регулярным выражением [ -]?(?:d*.)?d , чтобы извлечь первое вхождение чисел, таких как «1.23», «.99», «-100» и т.д. Последующая проверка чисел в оставшейся подстроке, записанной в suffix , определяет, является ли числовая подстрока в исходной строке допустимой.

 import org.apache.spark.sql.functions._
import spark.implicits._

case class RegexRes(prefix: String, suffix: String, value: Option[Double], pure_text: String)

val regexExtract = udf{ (s: String) =>
  val pattern = """(.*?)([ -]?(?:d*.)?d )(.*)""".r
  s match {
    case pattern(pfx, num, sfx) =>
      if (sfx.exists(_.isDigit))
        RegexRes("", "", None, s)
      else
        RegexRes(pfx, sfx, Some(num.toDouble), "")
    case _ =>
      RegexRes("", "", None, s)
  }
}

val df = Seq(
  "11 H", "111L", ".9", "<.004", ">= 0.78", "val<=0.6", "xyz 100 abc", "1-9", "aaa 100.3.4", "a1q1"
).toDF("result")

df.
  withColumn("regex_res", regexExtract($"result")).
  select($"result", $"regex_res.prefix", $"regex_res.suffix", $"regex_res.value", $"regex_res.pure_text").
  show
//  ----------- ------ ------ ----- ----------- 
// |     result|prefix|suffix|value|  pure_text|
//  ----------- ------ ------ ----- ----------- 
// |       11 H|      |     H| 11.0|           |
// |       111L|      |     L|111.0|           |
// |         .9|      |      |  0.9|           |
// |      <.004|     <|      |0.004|           |
// |    >= 0.78|   >= |      | 0.78|           |
// |   val<=0.6| val<=|      |  0.6|           |
// |xyz 100 abc|  xyz |   abc|100.0|           |
// |        1-9|      |      | null|        1-9|
// |aaa 100.3.4|      |      | null|aaa 100.3.4|
// |       a1q1|      |      | null|       a1q1|
//  ----------- ------ ------ ----- -----------