mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-07-06 11:52:10 +02:00
- Added triple query using triples-query-cassandra
- Added triples_query_client.py and a test
This commit is contained in:
parent
6de72d7567
commit
ee89a5d8e6
11 changed files with 350 additions and 8 deletions
6
scripts/triples-query-cassandra
Executable file
6
scripts/triples-query-cassandra
Executable file
|
|
@ -0,0 +1,6 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from trustgraph.query.triples.cassandra import run
|
||||||
|
|
||||||
|
run()
|
||||||
|
|
||||||
|
|
@ -20,4 +20,3 @@ print("Response...")
|
||||||
for val in resp:
|
for val in resp:
|
||||||
print(val.value)
|
print(val.value)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
70
tests/test-triples
Executable file
70
tests/test-triples
Executable file
|
|
@ -0,0 +1,70 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import pulsar
|
||||||
|
from trustgraph.triples_query_client import TriplesQueryClient
|
||||||
|
|
||||||
|
tq = TriplesQueryClient(pulsar_host="pulsar://localhost:6650")
|
||||||
|
|
||||||
|
e = "http://trustgraph.ai/e/shuttle"
|
||||||
|
|
||||||
|
limit=3
|
||||||
|
|
||||||
|
def dump(resp):
|
||||||
|
print("Response...")
|
||||||
|
for t in resp:
|
||||||
|
print(t.s.value, t.p.value, t.o.value)
|
||||||
|
|
||||||
|
print("-- * ---------------------------")
|
||||||
|
|
||||||
|
resp = tq.request(None, None, None, limit)
|
||||||
|
dump(resp)
|
||||||
|
|
||||||
|
print("-- s ---------------------------")
|
||||||
|
|
||||||
|
resp = tq.request("http://trustgraph.ai/e/shuttle", None, None, limit)
|
||||||
|
dump(resp)
|
||||||
|
|
||||||
|
print("-- p ---------------------------")
|
||||||
|
|
||||||
|
resp = tq.request(None, "http://trustgraph.ai/e/landed", None, limit)
|
||||||
|
dump(resp)
|
||||||
|
|
||||||
|
print("-- p ---------------------------")
|
||||||
|
|
||||||
|
resp = tq.request(None, None, "President", limit)
|
||||||
|
dump(resp)
|
||||||
|
|
||||||
|
print("-- sp ---------------------------")
|
||||||
|
|
||||||
|
resp = tq.request(
|
||||||
|
"http://trustgraph.ai/e/shuttle", "http://trustgraph.ai/e/landed", None,
|
||||||
|
limit
|
||||||
|
)
|
||||||
|
dump(resp)
|
||||||
|
|
||||||
|
print("-- so ---------------------------")
|
||||||
|
|
||||||
|
resp = tq.request(
|
||||||
|
"http://trustgraph.ai/e/shuttle", None, "the tower",
|
||||||
|
limit
|
||||||
|
)
|
||||||
|
dump(resp)
|
||||||
|
|
||||||
|
print("-- po ---------------------------")
|
||||||
|
|
||||||
|
resp = tq.request(
|
||||||
|
"http://trustgraph.ai/e/shuttle", "http://trustgraph.ai/e/landed",
|
||||||
|
None,
|
||||||
|
limit
|
||||||
|
)
|
||||||
|
dump(resp)
|
||||||
|
|
||||||
|
print("-- spo ---------------------------")
|
||||||
|
|
||||||
|
resp = tq.request(
|
||||||
|
"http://trustgraph.ai/e/shuttle", "http://trustgraph.ai/e/landed",
|
||||||
|
"on the concrete runway at Kennedy Space Center",
|
||||||
|
limit
|
||||||
|
)
|
||||||
|
dump(resp)
|
||||||
|
|
||||||
|
|
@ -67,7 +67,7 @@ class TrustGraph:
|
||||||
|
|
||||||
def get_s(self, s, limit=10):
|
def get_s(self, s, limit=10):
|
||||||
return self.session.execute(
|
return self.session.execute(
|
||||||
f"select p, o from triples where s = %s",
|
f"select p, o from triples where s = %s limit {limit}",
|
||||||
(s,)
|
(s,)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -97,7 +97,7 @@ class TrustGraph:
|
||||||
|
|
||||||
def get_os(self, o, s, limit=10):
|
def get_os(self, o, s, limit=10):
|
||||||
return self.session.execute(
|
return self.session.execute(
|
||||||
f"select s from triples where o = %s and s = %s limit {limit}",
|
f"select p from triples where o = %s and s = %s limit {limit}",
|
||||||
(o, s)
|
(o, s)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Graph embeddings query service. Input is vector, output is list of
|
Graph embeddings query service. Input is vector, output is list of
|
||||||
e
|
entities
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from .... direct.milvus import TripleVectors
|
from .... direct.milvus import TripleVectors
|
||||||
|
|
@ -39,6 +39,12 @@ class Processor(ConsumerProducer):
|
||||||
|
|
||||||
self.vecstore = TripleVectors(store_uri)
|
self.vecstore = TripleVectors(store_uri)
|
||||||
|
|
||||||
|
def create_value(self, ent):
|
||||||
|
if ent.startswith("http://") or ent.startswith("https://"):
|
||||||
|
return Value(value=ent, is_uri=True)
|
||||||
|
else:
|
||||||
|
return Value(value=ent, is_uri=False)
|
||||||
|
|
||||||
def handle(self, msg):
|
def handle(self, msg):
|
||||||
|
|
||||||
v = msg.value()
|
v = msg.value()
|
||||||
|
|
@ -64,10 +70,7 @@ class Processor(ConsumerProducer):
|
||||||
ents2 = []
|
ents2 = []
|
||||||
|
|
||||||
for ent in entities:
|
for ent in entities:
|
||||||
if ent.startswith("http://") or ent.startswith("https://"):
|
ents2.append(self.create_value(ent))
|
||||||
ents2.append(Value(value=ent, is_uri=True))
|
|
||||||
else:
|
|
||||||
ents2.append(Value(value=ent, is_uri=False))
|
|
||||||
|
|
||||||
entities = ents2
|
entities = ents2
|
||||||
|
|
||||||
|
|
|
||||||
0
trustgraph/query/triples/__init__.py
Normal file
0
trustgraph/query/triples/__init__.py
Normal file
3
trustgraph/query/triples/cassandra/__init__.py
Normal file
3
trustgraph/query/triples/cassandra/__init__.py
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
from . service import *
|
||||||
|
|
||||||
7
trustgraph/query/triples/cassandra/__main__.py
Executable file
7
trustgraph/query/triples/cassandra/__main__.py
Executable file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from . hf import run
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
run()
|
||||||
|
|
||||||
153
trustgraph/query/triples/cassandra/service.py
Executable file
153
trustgraph/query/triples/cassandra/service.py
Executable file
|
|
@ -0,0 +1,153 @@
|
||||||
|
|
||||||
|
"""
|
||||||
|
Triples query service. Input is a (s, p, o) triple, some values may be
|
||||||
|
null. Output is a list of triples.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .... direct.cassandra import TrustGraph
|
||||||
|
from .... schema import TriplesQueryRequest, TriplesQueryResponse
|
||||||
|
from .... schema import Value, Triple
|
||||||
|
from .... schema import triples_request_queue
|
||||||
|
from .... schema import triples_response_queue
|
||||||
|
from .... base import ConsumerProducer
|
||||||
|
|
||||||
|
module = ".".join(__name__.split(".")[1:-1])
|
||||||
|
|
||||||
|
default_input_queue = triples_request_queue
|
||||||
|
default_output_queue = triples_response_queue
|
||||||
|
default_subscriber = module
|
||||||
|
default_graph_host='localhost'
|
||||||
|
|
||||||
|
class Processor(ConsumerProducer):
|
||||||
|
|
||||||
|
def __init__(self, **params):
|
||||||
|
|
||||||
|
input_queue = params.get("input_queue", default_input_queue)
|
||||||
|
output_queue = params.get("output_queue", default_output_queue)
|
||||||
|
subscriber = params.get("subscriber", default_subscriber)
|
||||||
|
graph_host = params.get("graph_host", default_graph_host)
|
||||||
|
|
||||||
|
super(Processor, self).__init__(
|
||||||
|
**params | {
|
||||||
|
"input_queue": input_queue,
|
||||||
|
"output_queue": output_queue,
|
||||||
|
"subscriber": subscriber,
|
||||||
|
"input_schema": TriplesQueryRequest,
|
||||||
|
"output_schema": TriplesQueryResponse,
|
||||||
|
"graph_host": graph_host,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
self.tg = TrustGraph([graph_host])
|
||||||
|
|
||||||
|
def create_value(self, ent):
|
||||||
|
if ent.startswith("http://") or ent.startswith("https://"):
|
||||||
|
return Value(value=ent, is_uri=True)
|
||||||
|
else:
|
||||||
|
return Value(value=ent, is_uri=False)
|
||||||
|
|
||||||
|
def handle(self, msg):
|
||||||
|
|
||||||
|
v = msg.value()
|
||||||
|
|
||||||
|
# Sender-produced ID
|
||||||
|
id = msg.properties()["id"]
|
||||||
|
|
||||||
|
print(f"Handling input {id}...", flush=True)
|
||||||
|
|
||||||
|
triples = []
|
||||||
|
|
||||||
|
if v.s is not None:
|
||||||
|
if v.p is not None:
|
||||||
|
if v.o is not None:
|
||||||
|
resp = self.tg.get_spo(
|
||||||
|
v.s.value, v.p.value, v.o.value,
|
||||||
|
limit=v.limit
|
||||||
|
)
|
||||||
|
triples.append((v.s.value, v.p.value, v.o.value))
|
||||||
|
else:
|
||||||
|
resp = self.tg.get_sp(
|
||||||
|
v.s.value, v.p.value,
|
||||||
|
limit=v.limit
|
||||||
|
)
|
||||||
|
for t in resp:
|
||||||
|
triples.append((v.s.value, v.p.value, t.o))
|
||||||
|
else:
|
||||||
|
if v.o is not None:
|
||||||
|
resp = self.tg.get_os(
|
||||||
|
v.o.value, v.s.value,
|
||||||
|
limit=v.limit
|
||||||
|
)
|
||||||
|
for t in resp:
|
||||||
|
triples.append((v.s.value, t.p, v.o.value))
|
||||||
|
else:
|
||||||
|
resp = self.tg.get_s(
|
||||||
|
v.s.value,
|
||||||
|
limit=v.limit
|
||||||
|
)
|
||||||
|
for t in resp:
|
||||||
|
triples.append((v.s.value, t.p, t.o))
|
||||||
|
else:
|
||||||
|
if v.p is not None:
|
||||||
|
if v.o is not None:
|
||||||
|
resp = self.tg.get_po(
|
||||||
|
v.p.value, v.o.value,
|
||||||
|
limit=v.limit
|
||||||
|
)
|
||||||
|
for t in resp:
|
||||||
|
triples.append((t.s, v.p.value, v.o.value))
|
||||||
|
else:
|
||||||
|
resp = self.tg.get_p(
|
||||||
|
v.p.value,
|
||||||
|
limit=v.limit
|
||||||
|
)
|
||||||
|
for t in resp:
|
||||||
|
triples.append((t.s, v.p.value, t.o))
|
||||||
|
else:
|
||||||
|
if v.o is not None:
|
||||||
|
resp = self.tg.get_o(
|
||||||
|
v.o.value,
|
||||||
|
limit=v.limit
|
||||||
|
)
|
||||||
|
for t in resp:
|
||||||
|
triples.append((t.s, t.p, v.o.value))
|
||||||
|
else:
|
||||||
|
resp = self.tg.get_all(
|
||||||
|
limit=v.limit
|
||||||
|
)
|
||||||
|
for t in resp:
|
||||||
|
triples.append((t.s, t.p, t.o))
|
||||||
|
|
||||||
|
triples = [
|
||||||
|
Triple(
|
||||||
|
s=self.create_value(t[0]),
|
||||||
|
p=self.create_value(t[1]),
|
||||||
|
o=self.create_value(t[2])
|
||||||
|
)
|
||||||
|
for t in triples
|
||||||
|
]
|
||||||
|
|
||||||
|
print("Send response...", flush=True)
|
||||||
|
r = TriplesQueryResponse(triples=triples)
|
||||||
|
self.producer.send(r, properties={"id": id})
|
||||||
|
|
||||||
|
print("Done.", flush=True)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def add_args(parser):
|
||||||
|
|
||||||
|
ConsumerProducer.add_args(
|
||||||
|
parser, default_input_queue, default_subscriber,
|
||||||
|
default_output_queue,
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'-g', '--graph-host',
|
||||||
|
default="localhost",
|
||||||
|
help=f'Graph host (default: localhost)'
|
||||||
|
)
|
||||||
|
|
||||||
|
def run():
|
||||||
|
|
||||||
|
Processor.start(module, __doc__)
|
||||||
|
|
||||||
|
|
@ -34,6 +34,7 @@ class Processor(Consumer):
|
||||||
"input_queue": input_queue,
|
"input_queue": input_queue,
|
||||||
"subscriber": subscriber,
|
"subscriber": subscriber,
|
||||||
"input_schema": Triple,
|
"input_schema": Triple,
|
||||||
|
"graph_host": graph_host,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
100
trustgraph/triples_query_client.py
Normal file
100
trustgraph/triples_query_client.py
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import pulsar
|
||||||
|
import _pulsar
|
||||||
|
from pulsar.schema import JsonSchema
|
||||||
|
import hashlib
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
from . schema import TriplesQueryRequest, TriplesQueryResponse, Value
|
||||||
|
from . schema import triples_request_queue
|
||||||
|
from . schema import triples_response_queue
|
||||||
|
|
||||||
|
# Ugly
|
||||||
|
ERROR=_pulsar.LoggerLevel.Error
|
||||||
|
WARN=_pulsar.LoggerLevel.Warn
|
||||||
|
INFO=_pulsar.LoggerLevel.Info
|
||||||
|
DEBUG=_pulsar.LoggerLevel.Debug
|
||||||
|
|
||||||
|
class TriplesQueryClient:
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self, log_level=ERROR,
|
||||||
|
subscriber=None,
|
||||||
|
input_queue=None,
|
||||||
|
output_queue=None,
|
||||||
|
pulsar_host="pulsar://pulsar:6650",
|
||||||
|
):
|
||||||
|
|
||||||
|
if input_queue == None:
|
||||||
|
input_queue = triples_request_queue
|
||||||
|
|
||||||
|
if output_queue == None:
|
||||||
|
output_queue = triples_response_queue
|
||||||
|
|
||||||
|
if subscriber == None:
|
||||||
|
subscriber = str(uuid.uuid4())
|
||||||
|
|
||||||
|
self.client = pulsar.Client(
|
||||||
|
pulsar_host,
|
||||||
|
logger=pulsar.ConsoleLogger(log_level),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.producer = self.client.create_producer(
|
||||||
|
topic=input_queue,
|
||||||
|
schema=JsonSchema(TriplesQueryRequest),
|
||||||
|
chunking_enabled=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.consumer = self.client.subscribe(
|
||||||
|
output_queue, subscriber,
|
||||||
|
schema=JsonSchema(TriplesQueryResponse),
|
||||||
|
)
|
||||||
|
|
||||||
|
def create_value(self, ent):
|
||||||
|
|
||||||
|
if ent == None: return None
|
||||||
|
|
||||||
|
if ent.startswith("http://") or ent.startswith("https://"):
|
||||||
|
return Value(value=ent, is_uri=True)
|
||||||
|
|
||||||
|
return Value(value=ent, is_uri=False)
|
||||||
|
|
||||||
|
def request(self, s, p, o, limit=10, timeout=500):
|
||||||
|
|
||||||
|
id = str(uuid.uuid4())
|
||||||
|
|
||||||
|
r = TriplesQueryRequest(
|
||||||
|
s=self.create_value(s),
|
||||||
|
p=self.create_value(p),
|
||||||
|
o=self.create_value(o),
|
||||||
|
limit=limit,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.producer.send(r, properties={ "id": id })
|
||||||
|
|
||||||
|
while True:
|
||||||
|
|
||||||
|
msg = self.consumer.receive(timeout_millis=timeout * 1000)
|
||||||
|
|
||||||
|
mid = msg.properties()["id"]
|
||||||
|
|
||||||
|
if mid == id:
|
||||||
|
resp = msg.value().triples
|
||||||
|
self.consumer.acknowledge(msg)
|
||||||
|
return resp
|
||||||
|
|
||||||
|
# Ignore messages with wrong ID
|
||||||
|
self.consumer.acknowledge(msg)
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
|
||||||
|
if hasattr(self, "consumer"):
|
||||||
|
self.consumer.close()
|
||||||
|
|
||||||
|
if hasattr(self, "producer"):
|
||||||
|
self.producer.flush()
|
||||||
|
self.producer.close()
|
||||||
|
|
||||||
|
self.client.close()
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue