【问题标题】:Pyspark - get attribute names from json filePyspark - 从 json 文件中获取属性名称
【发布时间】:2019-06-02 11:57:57
【问题描述】:

我是 pyspark 的新手。我的要求是从嵌套的 json 文件中获取/提取属性名称。我尝试使用从 pandas 包导入的 json_normalize。它适用于直接属性,但从不获取 json 数组属性中的属性。我的 json 没有静态结构。它因我们收到的每份文件而异。有人可以帮我解释下面提供的小例子吗,

        {  
               "id":"1",
               "name":"a",
               "salaries":[  
                  {  
                     "salary":"1000"
                  },
                  {  
                     "salary":"5000"
                  }
               ],
               "states":{  
                  "state":"Karnataka",
                  "cities":[  
                     {  
                        "city":"Bangalore"
                     },
                     {  
                        "city":"Mysore"
                     }
                  ],
                  "state":"Tamil Nadu",
                  "cities":[  
                     {  
                        "city":"Chennai"
                     },
                     {  
                        "city":"Coimbatore"
                     }
                  ]
               }
            }  

特别是对于 json 数组元素..

预期输出: ID 姓名 工资.salary 状态.state states.cities.city``

【问题讨论】:

    标签: python apache-spark pyspark


    【解决方案1】:

    这是从json中提取所有嵌套属性的另一种解决方案

    import json
    
    result_set = set([])
    
    
    def parse_json_array(json_obj, parent_path):
        array_obj = list(json_obj)
        for i in range(0, len(array_obj)):
            json_ob = array_obj[i]
            if type(json_obj) == type(json_obj):
                parse_json(json_ob, parent_path)
        return None
    
    
    def parse_json(json_obj, parent_path):
        for key in json_obj.keys():
            key_value = json_obj.get(key)
            # if isinstance(a, dict):
            if type(key_value) == type(json_obj):
                parse_json(key_value, str(key) if parent_path == "" else parent_path + "." + str(key))
            elif type(key_value) == type(list(json_obj)):
                parse_json_array(key_value, str(key) if parent_path == "" else parent_path + "." + str(key))
            result_set.add((parent_path + "." + key).encode('ascii', 'ignore'))
        return None
    
    
    
    file_name = "C:/input/sample.json"
    file_data = open(file_name, "r")
    json_data = json.load(file_data)
    print json_data
    
    parse_json(json_data, "")
    print list(result_set)
    

    输出:

    {u'states': {u'state': u'Tamil Nadu', u'cities': [{u'city': u'Chennai'}, {u'city': u'Coimbatore'}]}, u'id': u'1', u'salaries': [{u'salary': u'1000'}, {u'salary': u'5000'}], u'name': u'a'}
    ['states.cities.city', 'states.cities', '.id', 'states.state', 'salaries.salary', '.salaries', '.states', '.name']
    

    注意:

    My Python version: 2.7 
    

    【讨论】:

      【解决方案2】:

      你也可以这样做。

      data = { "id":"1", "name":"a", "salaries":[ { "salary":"1000" }, { "salary":"5000" } ], "states":{ "state":"Karnataka", "cities":[ { "city":"Bangalore" }, { "city":"Mysore" } ], "state":"Tamil Nadu", "cities":[ { "city":"Chennai" }, { "city":"Coimbatore" } ] } }
      
      
      
      def dict_ittr(lin,data):
      
          for k, v in data.items():
              if type(v)is list:
                  for l in v:
                     dict_ittr(lin+"."+k,l)
              elif type(v)is dict:
                  dict_ittr(lin+"."+k,v)
                  pass
              else:
                  print lin+"."+k
      
      dict_ittr("",data)
      

      输出

      .states.state
      .states.cities.city
      .states.cities.city
      .id
      .salaries.salary
      .salaries.salary
      .name
      

      【讨论】:

        【解决方案3】:

        如果您将 json 视为 python 字典,这应该可以工作。

        我刚刚写了一个简单的递归程序。

        脚本

        import json
        
        def js_r(filename):
            with open(filename) as f_in:
                return(json.load(f_in))
        
        g = js_r("city.json")
        answer_d = {}
        def base_line(g, answer_d):
            for key in g.keys():
                answer_d[key] = {}
            return answer_d
        
        answer_d = base_line(g, answer_d)
        def recurser_func(g, answer_d):
            for k in g.keys():
                if type(g[k]) == type([]): #If the value is a list
                    answer_d[k] = {list(g[k][0].keys())[0]:{}}
        
                if type(g[k]) == type({}): #If the value is a dictionary
                    answer_d[k] = {list(g[k].keys())[0]: {}} #set key equal to 
                    answer_d[k] = recurser_func(g[k], answer_d[k])
            return answer_d
        recurser_func(g,answer_d)
        
        
        def printer_func(answer_d, list_to_print, parent):
            for k in answer_d.keys():
                if len(answer_d[k].keys()) == 1:
                    list_to_print.append(parent)
                    list_to_print[-1] += k
                    list_to_print[-1] += "." + str(list(answer_d[k].keys())[0])
                if len(answer_d[k].keys()) == 0:
                    list_to_print.append(parent)
                    list_to_print[-1] += k
                if len(answer_d[k].keys()) > 1:
                    printer_func(answer_d[k], list_to_print, k + ".")
            return list_to_print
        
        
        
        l = printer_func(answer_d, [], "")
        final = " ".join(l)
        print(final)
        

        说明

        base_line 为您的所有基本键创建一个字典。

        recursur_func 检查键的值是列表还是字典,然后根据需要添加到答案字典中,直到 answer_d 看起来像:{'id': {}, 'name': {}, 'salaries': {'salary': {}}, 'states': {'state': {}, 'cities': {'city': {}}}}

        在调用这两个函数之后,您在某种意义上就有了一个键字典。那么printer_func是一个递归函数,可以根据需要打印。

        注意:

        您的问题与以下问题类似:Get all keys of a nested dictionary 但由于您有一个嵌套列表/字典而不仅仅是一个嵌套字典,因此他们的答案对您不起作用,但是关于该问题的主题有更多讨论如果您想了解更多信息

        编辑 1

        我的python版本是3.7.1

        我在顶部添加了一个 json 文件打开器。我假设 json 被命名为 city.json 并且在同一个目录中

        编辑 2:更详尽的解释

        我发现处理数据的主要困难是您可以拥有无​​限嵌套的列表和字典。这使它变得复杂。由于它是无限可能的嵌套,因此我认为这是一个递归问题。

        因此,我构建了一个字典字典,表示您正在寻找的关键结构。首先,我从基线开始。

        base_line 使{'id': {}, 'name': {}, 'salaries': {}, 'states': {}} 这是一个空字典的字典。我知道当你打印时。每个关键结构(如states.state)都以这些词之一开头。

        递归

        然后我使用recursur_func 添加所有子键。 当给定字典 g 时,此函数 for 循环遍历该字典中的所有键,并且(假设 answer_d 具有 g 具有的每个键)每个键都会将该键子添加到 answer_d。

        如果孩子是一本字典。然后我用给定的字典g 进行递归,现在它是属于儿童的字典的子部分,而 answer_d 是属于儿童的 answer_d 的子部分。

        【讨论】:

        • 感谢您的解释。如果我将相同的 json 内容存储在文件中(如 .json),则会出现以下错误, answer_d[k] = {list(g[k][0].keys())[0]:{}} AttributeError : 'str' 对象没有属性 'keys' 。我发现这里的代码有点难以理解。检查列表的原因是为了找到json数组?? ..再次感谢您的帮助!!
        猜你喜欢
        • 1970-01-01
        • 2018-11-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多