python-3.xhivepysparkapache-spark-sqlthrift-protocol

How to connect spark with hive using pyspark?


I am trying to read hive tables using pyspark, remotely. It states the error that it is unable to connect to Hive Metastore client.

I have read multiple answers on SO and other sources, they were mostly configurations but none of them could address why am I unable to connect remotely. I read the documentation and observed that without making changes in any configuration file, we can connect spark with hive. Note: I have port-forwarded a machine where hive is running and brought it available to localhost:10000. I even connected the same using presto and was able to run queries on hive.

The code is:

from pyspark import SparkContext, SparkConf
from pyspark.sql import SparkSession, HiveContext
SparkContext.setSystemProperty("hive.metastore.uris", "thrift://localhost:9083")
sparkSession = (SparkSession
                .builder
                .appName('example-pyspark-read-and-write-from-hive')
                .enableHiveSupport()
                .getOrCreate())
data = [('First', 1), ('Second', 2), ('Third', 3), ('Fourth', 4), ('Fifth', 5)]
df = sparkSession.createDataFrame(data)
df.write.saveAsTable('example')

I expect the output to be an acknowledgment of table being saved but instead, I am facing this error.

Abstract error is:

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "/usr/local/spark/python/pyspark/sql/readwriter.py", line 775, in saveAsTable
    self._jwrite.saveAsTable(name)
  File "/usr/local/spark/python/lib/py4j-0.10.7-src.zip/py4j/java_gateway.py", line 1257, in __call__
  File "/usr/local/spark/python/pyspark/sql/utils.py", line 69, in deco
    raise AnalysisException(s.split(': ', 1)[1], stackTrace)
pyspark.sql.utils.AnalysisException: 'java.lang.RuntimeException: java.lang.RuntimeException: Unable to instantiate org.apache.hadoop.hive.ql.metadata.SessionHiveMetaStoreClient;'

I have fired a command:

ssh -i ~/.ssh/id_rsa_sc -L 9000:A.B.C.D:8080 -L 9083:E.F.G.H:9083 -L 10000:E.F.G.H:10000 ubuntu@I.J.K.l

When I check for ports 10000 and 9083 via the commands:

aviral@versinator:~/testing-spark-hive$ nc -zv localhost 10000
Connection to localhost 10000 port [tcp/webmin] succeeded!
aviral@versinator:~/testing-spark-hive$ nc -zv localhost 9083
Connection to localhost 9083 port [tcp/*] succeeded!

Upon running the script, I get the following error:

Caused by: java.net.UnknownHostException: ip-172-16-1-101.ap-south-1.compute.internal
    ... 45 more

Solution

  • The catch is in letting the hive configs being stored while creating the spark session itself.

    sparkSession = (SparkSession
                    .builder
                    .appName('example-pyspark-read-and-write-from-hive')
                    .config("hive.metastore.uris", "thrift://localhost:9083", conf=SparkConf())
                    .enableHiveSupport()
                    .getOrCreate()
                    )
    

    It should be noted that no changes in spark conf are required, even serverless services like AWS Glue can have such connections.

    For full code:

    from pyspark import SparkContext, SparkConf
    from pyspark.conf import SparkConf
    from pyspark.sql import SparkSession, HiveContext
    """
    SparkSession ss = SparkSession
    .builder()
    .appName(" Hive example")
    .config("hive.metastore.uris", "thrift://localhost:9083")
    .enableHiveSupport()
    .getOrCreate();
    """
    
    sparkSession = (SparkSession
                    .builder
                    .appName('example-pyspark-read-and-write-from-hive')
                    .config("hive.metastore.uris", "thrift://localhost:9083", conf=SparkConf())
                    .enableHiveSupport()
                    .getOrCreate()
                    )
    data = [('First', 1), ('Second', 2), ('Third', 3), ('Fourth', 4), ('Fifth', 5)]
    df = sparkSession.createDataFrame(data)
    # Write into Hive
    #df.write.saveAsTable('example')
    
    df_load = sparkSession.sql('SELECT * FROM example')
    df_load.show()
    print(df_load.show())