py2neo command in neo4j BOLT driver - python

I have a command written in python using the py2neo to access the name of an exchange. This works.
graph = Graph()
stmt = 'MATCH (i:Index{uniqueID: 'SPY'})-[r:belongsTo]->(e:Exchange) RETURN e.name'
exchName = graph.cypher.execute(stmt)[0][0]
Can this be converted to a BOLT neo4j-driver statement? I always get an error. I want to avoid an iterator statement where I loop through the StatementResult.
driver = GraphDatabase.driver("bolt://localhost", auth=basic_auth("neo4j", "neo4j"))
session = driver.session()
stmt = 'MATCH (i:Index{uniqueID: 'SPY'})-[r:belongsTo]->(e:Exchange) RETURN e.name'
exchName = session.run(stmt)[0][0]
TypeError: 'StatementResult' object is not subscriptable

Try to store the results of session.run() in a list to retain them:
driver = GraphDatabase.driver("bolt://localhost", auth=basic_auth("neo4j", "neo4j"))
session = driver.session()
stmt = 'MATCH (i:Index{uniqueID: 'SPY'})-[r:belongsTo]->(e:Exchange) RETURN e.name'
# transform to list to retain result
exchName = list(session.run(stmt))[0][0]
See the docs: http://neo4j.com/docs/developer-manual/current/#result-retain

Related

Use cursor.executemany instead of cursor.execute with tying panda header to sql variables

I have a python script that updates rows in an oracle sql table correctly, however I am using cursor.execute and try/except so if one update fails, it kills the whole run.
I want to be able to have it run through the whole update and just log the error and move onto the next one, which is where cursor.executemany comes in.
https://cx-oracle.readthedocs.io/en/latest/user_guide/batch_statement.html
Here is the script, it works great, except for the all or nothing error approach.
#oracle sql update statement for SHRTCKN
banner_shrtckn_update = """
UPDATE SATURN.SHRTCKN A
SET A.SHRTCKN_COURSE_COMMENT = :course_comment,
A.SHRTCKN_REPEAT_COURSE_IND = :repeat_ind,
A.SHRTCKN_ACTIVITY_DATE = SYSDATE,
A.SHRTCKN_USER_ID = 'STU00940',
A.SHRTCKN_DATA_ORIGIN = 'APPWORX'
WHERE A.SHRTCKN_PIDM = gb_common.f_get_pidm(:id) AND
A.SHRTCKN_TERM_CODE = :term_code AND
A.SHRTCKN_SEQ_NO = :seqno AND
A.SHRTCKN_CRN = :crn AND
A.SHRTCKN_SUBJ_CODE = :subj_code AND
A.SHRTCKN_CRSE_NUMB = :crse_numb
"""
def main():
# get time of run and current year
now = datetime.datetime.now()
year = str(now.year)+"40"
# configure connection strings for banner PROD
db_pass = os.environ['DB_PASSWORD']
dsn = cx_Oracle.makedsn(host='FAKE', port='1521', service_name='TEST.FAKE.BLAH')
try: # initiate banner db connection -- PROD
banner_cnxn = cx_Oracle.connect(user=config.db_test['user'], password = db_pass, dsn=dsn)
writeLog("---- Oracle Connection Made ----")
insertCount = 0
for index, row in df.iterrows():
shrtcknupdate(row,banner_cnxn)
insertCount = insertCount + 1
banner_cnxn.commit()
banner_cnxn.close()
writeLog(str(insertCount)+" rows updated")
except Exception as e:
print("Error: "+str(e))
writeLog("Error: "+str(e))
def writeLog(content):
print(content)
log.write(str(datetime.date.today())+" "+content+"\n")
#define the variable connection between panda/csv and SHRTCKN table
def shrtcknupdate(row, connection):
sql = banner_shrtckn_update
variables = {
'id' : row.Bear_Nbr,
'term_code' : row.Past_Term,
'seqno' : row.Seq_No,
'crn' : row.Past_CRN,
'subj_code' : row.Past_Prefix,
'crse_numb' : row.Past_Number,
'course_comment' : row.Past_Course_Comment,
'repeat_ind' : row.Past_Repeat_Ind
}
cursor = connection.cursor()
cursor.execute(sql, variables)
if __name__ == "__main__":
writeLog("-------- Process Start --------")
main()
writeLog("-------- Process End --------")
The executemany option, I can turn on batcherrors=True
and it will do exactly what I need.
The problem I am running into, is if I get rid of the for loop that runs through the excel/panda dataframe to update the oracle sql rows, which is not needed when doing the update in batch, then how do I attach the column headers to the sql update statement.
If I leave in the for loop, I get this error when using executemany:
Error: parameters should be a list of sequences/dictionaries or an integer specifying the number of times to execute the statement
For named binds, you need to provide a list of dictionaries. This list can be obtained by to_dict(orient='records'):
‘records’ : list like [{column -> value}, … , {column -> value}]
banner_shrtckn_update = """
UPDATE SATURN.SHRTCKN A
SET A.SHRTCKN_COURSE_COMMENT = :Past_Course_Comment,
A.SHRTCKN_REPEAT_COURSE_IND = :Past_Repeat_Ind,
A.SHRTCKN_ACTIVITY_DATE = SYSDATE,
A.SHRTCKN_USER_ID = 'STU00940',
A.SHRTCKN_DATA_ORIGIN = 'APPWORX'
WHERE A.SHRTCKN_PIDM = gb_common.f_get_pidm(:Bear_Nbr) AND
A.SHRTCKN_TERM_CODE = :Past_Term AND
A.SHRTCKN_SEQ_NO = :Seq_No AND
A.SHRTCKN_CRN = :Past_CRN AND
A.SHRTCKN_SUBJ_CODE = :Past_Prefix AND
A.SHRTCKN_CRSE_NUMB = :Past_Number
"""
def main():
# get time of run and current year
now = datetime.datetime.now()
year = str(now.year)+"40"
# configure connection strings for banner PROD
db_pass = os.environ['DB_PASSWORD']
dsn = cx_Oracle.makedsn(host='FAKE', port='1521', service_name='TEST.FAKE.BLAH')
try: # initiate banner db connection -- PROD
banner_cnxn = cx_Oracle.connect(user=config.db_test['user'], password = db_pass, dsn=dsn)
writeLog("---- Oracle Connection Made ----")
# batch execute banner_shrtckn_update
cursor = banner_cnxn.cursor()
data = df[['Bear_Nbr', 'Past_Term', 'Seq_No', 'Past_CRN', 'Past_Prefix', 'Past_Number', 'Past_Course_Comment', 'Past_Repeat_Ind']].to_dict('records')
cursor.executemany(banner_shrtckn_update, data, batcherrors=True)
for error in cursor.getbatcherrors():
writeLog(f"Error {error.message} at row offset {error.offset}")
banner_cnxn.commit()
banner_cnxn.close()
except Exception as e:
print("Error: "+str(e))
writeLog("Error: "+str(e))
This isn't described in detail in the documenation, but you can find an example for named binds in python-cx_Oracle/samples/bind_insert.py.
(Please note that I adjusted the variable names in your sql statement to the dataframe column names to avoid renaming of the columns at creating data.)

passing parameters in neo4j using python

I want to pass parameter in CREATE using Python
e.g:
'''
n = "abc"
a = 1234
cqlCreate = "CREATE (cornell:university { name: $n,yob:$a})"
''''
but it dosen't work.. any suggestions please
It actually depends on the Python driver that you are using to connect to Neo4j (check https://neo4j.com/developer/python/ to see the list of available drivers). If you are using the official neo4j-driver, the code you wrote is correct. In order execute the Cypher query, you could do something like this:
from neo4j import GraphDatabase
uri = # insert neo4j uri
user = # insert neo4j username
password = # insert neo4j password
n = "abc"
a = 1234
query = "CREATE (cornell:university { name: $n,yob:$a})"
driver = GraphDatabase.driver(uri, auth=(user, password))
session = driver.session()
result = session.run(query, n=n, a=a)
session.close()
driver.close()
Although âńōŋŷXmoůŜ's answer will probably work, it is not recommended way to it.
See also:
https://neo4j.com/docs/api/python-driver/current/api.html
You can use the f-strings in Python. See example below. Note that
You need to use {{ as escape character for {
2 You need to use \ as escape character for "
n = "abc"
a = 1234
cqlCreate = f"CREATE (cornell:university {{name: \"{n}\", yob: {a}}})"
print (cqlCreate)
Result:
CREATE (cornell:university {name: "abc", yob: 1234})
reference: https://www.python.org/dev/peps/pep-0498/

Fetching results from cypher bolt statement

I am trying to access neo4j using neo4j python driver.I am running the following code to get a property of a thing A., I open the driver and session directly from GraphDatabase of neo4j and use session.run() to execute graph queries. These queries return a BoltStatementResult object.My question is how this object can be converted to actual result that I need(Property of thing A).?
from neo4j import GraphDatabase
uri = "bolt://abc:7687"
driver = GraphDatabase.driver(uri, auth=("neo4j", "password"))
def matchQuestion(tx, intent,thing):
result = tx.run("MATCH (e:thing) WHERE e.name = {thing}"
"RETURN e.description", thing=thing)
print(result)
with driver.session() as session:
session.read_transaction(matchQuestion, "define","A")
result = tx.run("MATCH (e:thing) WHERE e.name = {thing}"
"RETURN e.description AS description", thing=thing)
for line in result:
print line["description"]
or
print result.single()
You could also specify the item position like -
print result.single()[0]

Using Python elastisearch_dsl with nested objects

I want to try and use elasticsearch_dsl with python for the following
import elasticsearch
es_server = 'my_server_name'
es_port = '9200'
es_index_name = 'my_index_name'
es_connection = Elasticsearch([{'host': es_server, 'port': es_port}])
es_query = '{"query":{"bool":{"must":[{"term":{"data.party.fullName":"john do"}}],"must_not":[],"should":[]}},"from":0,"size":1,"sort":[],"facets":{}}'
my_results = es_connection.search(index=es_index_name, body=es_query)
print my_results
es_query ='{"query": {"nested" : {"filter" : {"term" : {"party.phoneList.phoneFullNumber" : "4081234567"}},"path" : "party.phoneList"}},"from" :0,"size" : 1}';
my_results = es_connection.search(index=es_index_name, body=es_query)
print my_results
I am able to get the 1st query but am not sure on the second one
from elasticsearch import Elasticsearch
from elasticsearch_dsl import Search, Q
client = Elasticsearch('my_server:9200')
s = Search(using=client, index = "my_index").query("term",fullName="john do ")
response = s.execute()
print response
Not sure how to do the query using DSL for the nested object party.phoneList.phoneFullNumber
New to ES and hence could not figure out how to do the nested objects.
I looked at https://github.com/elastic/elasticsearch-dsl-py/issues/28 and could not quite figure out.
Thanks !
Just use __ instead of . to get around python's limitations and the nested query:
s = Search(using=client, index = "my_index")
s = s.query("nested",
path="party.phoneList",
query=Q("term", party__phoneList__phoneFullNumber="4081234567")
)

Neo4j Bolt StatementResult to Pandas DataFrame

Based on example from Neo4j
from neo4j.v1 import GraphDatabase, basic_auth
driver = GraphDatabase.driver("bolt://localhost", auth=basic_auth("neo4j", "neo4j"))
session = driver.session()
session.run("CREATE (a:Person {name:'Arthur', title:'King'})")
result = session.run("MATCH (a:Person) WHERE a.name = 'Arthur' RETURN a.name AS name, a.title AS title")
for record in result:
print("%s %s" % (record["title"], record["name"]))
session.close()
Here result is of datatype neo4j.v1.session.StatementResult. How to access this data in pandas dataframe without explicitly iterating?
pd.DataFrame.from_records(result) doesn't seem to help.
This is what I have using list comprehension
resultlist = [[record['title'], record['name']] for record in result]
pd.DataFrame.from_records(resultlist, columns=['title', 'name'])
The best I can come up with is a list comprehension similar to yours, but less verbose:
df = pd.DataFrame([r.values() for r in result], columns=result.keys())
The py2neo package seems to be more suitable for DataFrames, as it's fairly straightforward to return a list of dictionaries. Here's the equivalent code using py2neo:
import py2neo
# Some of these keyword arguments are unnecessary, as they are the default values.
graph = py2neo.Graph(bolt=True, host='localhost', user='neo4j', password='neo4j')
graph.run("CREATE (a:Person {name:'Arthur', title:'King'})")
query = "MATCH (a:Person) WHERE a.name = 'Arthur' RETURN a.name AS name, a.title AS title"
df = pd.DataFrame(graph.data(query))
Casting result records into dictionaries does the trick:
df = pd.DataFrame([dict(record) for record in result])
What about:
from neo4j.v1 import GraphDatabase
from pandas import DataFrame
uri = "bolt://localhost:7687"
driver = GraphDatabase.driver(uri, auth=("",""))
get_instances = """MATCH (n)--(m)
RETURN n
LIMIT 10
"""
with driver.session() as graphDB_Session:
result = graphDB_Session.run(get_instances)
df = DataFrame(result.records(), columns=result.keys())
Works for me.
In the V4 of py2neo, the conversion to pandas DataFrame is even easier.
import py2neo
# Some of these keyword arguments are unnecessary, as they are the default values.
graph = py2neo.Graph(uri, user=username, password=password)
df = graph.run("Your query goes here").to_data_frame()

Categories