docstr: Generate unique index value of categorical features. The resulting index would
  start from 1 with 0 reserved for unknown features.
  
  :param df: a pyspark.sql.dataframe.DataFrame to be processed.
  :param columns: str, dict or a list of str, dict, target column(s) to generate StringIndex.
   dict is a mapping of source column names -> target column name if needs to combine multiple
   source columns to generate index.
   For example: {'src_cols':['a_user', 'b_user'], 'col_name':'user'}.
  :param freq_limit: int, dict or None. Categories with a count/frequency below freq_limit
         will be omitted from the encoding. Can be represented as either an integer,
         dict. For instance, 15, {'col_4': 10, 'col_5': 2} etc. Default is None,
         and in this case all the categories that appear will be encoded.
  :param order_by_freq: boolean, whether the result StringIndex will assign smaller indices
         to values with more frequencies. Default is False and in this case frequency order
         may not be preserved when assigning indices.
  :param do_split: bool, whether need to split column value to array to generate index.
  Default is False.
  :param sep: str, a string representing a regular expression to split a column value.
   Default is ','.
  
  :return: A StringIndex or a list of StringIndex.
docstr_tok: ["Generate","unique","index","value","of","categorical","features",".","The","resulting","index","would","start","from","1","with","0","reserved","for","unknown","features",".",":","param","df",":","a","pyspark.sql.dataframe.DataFrame","to","be","processed",".",":","param","columns",":","str",",","dict","or","a","list","of","str",",","dict",",","target","column","(","s",")","to","generate","StringIndex",".","dict","is","a","mapping","of","source","column","names","-",">","target","column","name","if","needs","to","combine","multiple","source","columns","to","generate","index",".","For","example",":","{","'src_cols","'",":","[","'a_user","'",",","'b_user","'","]",",","'col_name","'",":","'user","'","}",".",":","param","freq_limit",":","int",",","dict","or","None",".","Categories","with","a","count\/frequency","below","freq_limit","will","be","omitted","from","the","encoding",".","Can","be","represented","as","either","an","integer",",","dict",".","For","instance",",","15",",","{","'col_4","'",":","10",",","'col_5","'",":","2","}","etc",".","Default","is","None",",","and","in","this","case","all","the","categories","that","appear","will","be","encoded",".",":","param","order_by_freq",":","boolean",",","whether","the","result","StringIndex","will","assign","smaller","indices","to","values","with","more","frequencies",".","Default","is","False","and","in","this","case","frequency","order","may","not","be","preserved","when","assigning","indices",".",":","param","do_split",":","bool",",","whether","need","to","split","column","value","to","array","to","generate","index",".","Default","is","False",".",":","param","sep",":","str",",","a","string","representing","a","regular","expression","to","split","a","column","value",".","Default","is","'",",","'",".",":","return",":","A","StringIndex","or","a","list","of","StringIndex","."]
code: def gen_string_idx(
      self,
      df: "SparkDataFrame",
      columns: Union[str, List[str]],
      freq_limit: Optional[Union[int, Dict[str, int]]] = None,
      order_by_freq: bool = False,
      do_split: bool = False,
      sep: str = ",",
  ) -> Union["StringIndex", List["StringIndex"]]:
      """
      Generate unique index value of categorical features. The resulting index would
      start from 1 with 0 reserved for unknown features.
  
      :param df: a pyspark.sql.dataframe.DataFrame to be processed.
      :param columns: str, dict or a list of str, dict, target column(s) to generate StringIndex.
       dict is a mapping of source column names -> target column name if needs to combine multiple
       source columns to generate index.
       For example: {'src_cols':['a_user', 'b_user'], 'col_name':'user'}.
      :param freq_limit: int, dict or None. Categories with a count/frequency below freq_limit
             will be omitted from the encoding. Can be represented as either an integer,
             dict. For instance, 15, {'col_4': 10, 'col_5': 2} etc. Default is None,
             and in this case all the categories that appear will be encoded.
      :param order_by_freq: boolean, whether the result StringIndex will assign smaller indices
             to values with more frequencies. Default is False and in this case frequency order
             may not be preserved when assigning indices.
      :param do_split: bool, whether need to split column value to array to generate index.
      Default is False.
      :param sep: str, a string representing a regular expression to split a column value.
       Default is ','.
  
      :return: A StringIndex or a list of StringIndex.
      """
      if columns is None:
          invalidInputError(
              False,
              "columns should be str or a list of str, but got None.",
          )
      is_single_column = False
      if not isinstance(columns, list):
          is_single_column = True
          columns = [columns]
      src_columns = []
      for c in columns:
          if isinstance(c, dict):
              if "src_cols" in c:
                  src_columns.extend(c["src_cols"])
          else:
              src_columns.append(c)
      check_col_exists(df, src_columns)
      if freq_limit:
          if isinstance(freq_limit, int):
              freq_limit = str(freq_limit)  # type:ignore
          elif isinstance(freq_limit, dict):
              freq_limit = ",".join(
                  str(k) + ":" + str(v)  # type:ignore
                  for k, v in freq_limit.items()
              )
          else:
              invalidInputError(
                  False,
                  "freq_limit only supports int, dict or None, but get "
                  + freq_limit.__class__.__name__,
              )
      out_columns = []
      simple_columns = []  # type: ignore
      df_id_list = []
      for c in columns:
          # union column
          if isinstance(c, dict):
              if "src_cols" in c:
                  src_cols = c["src_cols"]
              else:
                  invalidInputError(
                      False,
                      "Union columns must has argument 'src_cols'",
                  )
              if "col_name" in c:
                  col_name = c["col_name"]
              else:
                  col_name = src_cols[0] + "_union"
              # process simple columns
              if simple_columns:
                  simple_df_id_list = generate_string_idx(
                      df, simple_columns, freq_limit, order_by_freq
                  )
                  df_id_list.extend(simple_df_id_list)
                  simple_columns = []
              # process union columns
              for i, src_c in enumerate(src_cols):
                  if i == 0:
                      dict_df = df.select(F.col(src_c).alias(col_name))
                  else:
                      dict_df = dict_df.union(
                          df.select(F.col(src_c).alias(col_name))
                      )
              union_id_list = generate_string_idx(
                  dict_df, [col_name], freq_limit, order_by_freq
              )
              df_id_list.extend(union_id_list)
              out_columns.append(col_name)
          # single column
          else:
              if do_split:
                  dict_df = df.select(F.col(c))
                  dict_df = dict_df.withColumn(
                      c, F.explode(F.split(c, sep))
                  )
                  split_id_list = generate_string_idx(
                      dict_df, [c], freq_limit, order_by_freq
                  )
                  df_id_list.extend(split_id_list)
                  out_columns.append(c)
              else:
                  simple_columns.append(c)
                  out_columns.append(c)
      if simple_columns:
          simple_df_id_list = generate_string_idx(
              df, simple_columns, freq_limit, order_by_freq
          )
          df_id_list.extend(simple_df_id_list)
  
      string_idx_list = list(
          map(
              lambda x: StringIndex(x[0], x[1]),
              zip(df_id_list, out_columns),
          )
      )
  
      # If input is a single column (not a list), then the output would be a single StringIndex.
      if len(string_idx_list) == 1 and is_single_column:
          return string_idx_list[0]
      else:
          return string_idx_list
  
imports: import pyspark.sql.functions
  from pyspark.sql import Row
  from pyspark.sql.types import IntegerType, StructType, StringType, StructField
  from bigdl.dllib.utils.log4Error import invalidInputError
  from bigdl.orca.data import SparkXShards
  from bigdl.orca import OrcaContext
  from pyspark.ml.feature import MinMaxScaler
  from pyspark.ml.feature import StandardScaler
  from pyspark.ml.feature import VectorAssembler
  from pyspark.ml import Pipeline
  from bigdl.orca.data.utils import *
  import uuid
  from typing import TYPE_CHECKING, Tuple, Union, List
label_desc: Use image node_id 5 for calling the StringIndexer obj's underlying member method code with example usage: obj.gen_string_idx(df, columns, freq_limit, order_by_freq, do_split, sep) and returns: string_idx_list, string_idx_list