tempest_db 0.12.1 → 0.13.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bd0251246d8e34f45d4a9a642a5c0437787969eb
4
+ data.tar.gz: 82770a53fbac19c30faf7608011199b9b353e4c8
5
+ SHA512:
6
+ metadata.gz: e6b6e00c7e9165ed2200a9a7edcf08b9b97f0c07f6988f39403c59214ad455b49e452247926e60b737eeb65543e7dd3a9d4fc2fd7f7a268d47cece4988f19bcf
7
+ data.tar.gz: 8b3887040d8ec3ebe1c5120584e6f31e03ec0bf7c2a27ece714b88160562054a99dea22d83869fa732d46c32807ec39a7c56cf97a3debbe11429326a1d8773c1
@@ -8,10 +8,11 @@ module Teapot
8
8
  @executor = nil
9
9
  @transport = nil
10
10
 
11
- def initialize(server, port)
11
+ def initialize(server, port, max_retries = 3)
12
12
  @server = server
13
13
  @port = port
14
14
  @executor = init_executor(init_protocol())
15
+ @max_retries = max_retries
15
16
  end
16
17
 
17
18
  def init_protocol
@@ -32,6 +33,20 @@ module Teapot
32
33
  @executor
33
34
  end
34
35
 
36
+
37
+ def with_retries(&f)
38
+ (0..@max_retries).each do |retry_count|
39
+ begin
40
+ return f.call(get_executor)
41
+ rescue Thrift::TransportException, IOError
42
+ if retry_count == @max_retries then
43
+ raise # re-throw exception back to user
44
+ else
45
+ puts "For call #{caller[3][/`([^']*)'/, 1]}, attempting to reconnect to #{@server}:#{@port}..."
46
+ @executor = init_executor(init_protocol())
47
+ end
48
+ end
49
+ end
50
+ end
35
51
  end
36
52
  end
37
-
@@ -86,13 +86,13 @@ module Teapot
86
86
  raise ::Thrift::ApplicationException.new(::Thrift::ApplicationException::MISSING_RESULT, 'kStepInNeighborsFiltered failed: unknown result')
87
87
  end
88
88
 
89
- def ppr(edgeType, seeds, pageRankParams)
90
- send_ppr(edgeType, seeds, pageRankParams)
89
+ def ppr(edgeType, seeds, seedType, targetType, pageRankParams)
90
+ send_ppr(edgeType, seeds, seedType, targetType, pageRankParams)
91
91
  return recv_ppr()
92
92
  end
93
93
 
94
- def send_ppr(edgeType, seeds, pageRankParams)
95
- send_message('ppr', Ppr_args, :edgeType => edgeType, :seeds => seeds, :pageRankParams => pageRankParams)
94
+ def send_ppr(edgeType, seeds, seedType, targetType, pageRankParams)
95
+ send_message('ppr', Ppr_args, :edgeType => edgeType, :seeds => seeds, :seedType => seedType, :targetType => targetType, :pageRankParams => pageRankParams)
96
96
  end
97
97
 
98
98
  def recv_ppr()
@@ -189,7 +189,7 @@ module Teapot
189
189
  args = read_args(iprot, Ppr_args)
190
190
  result = Ppr_result.new()
191
191
  begin
192
- result.success = @handler.ppr(args.edgeType, args.seeds, args.pageRankParams)
192
+ result.success = @handler.ppr(args.edgeType, args.seeds, args.seedType, args.targetType, args.pageRankParams)
193
193
  rescue ::Teapot::TempestDB::UndefinedGraphException => error1
194
194
  result.error1 = error1
195
195
  rescue ::InvalidNodeIdException => error2
@@ -399,11 +399,15 @@ module Teapot
399
399
  include ::Thrift::Struct, ::Thrift::Struct_Union
400
400
  EDGETYPE = 1
401
401
  SEEDS = 2
402
- PAGERANKPARAMS = 3
402
+ SEEDTYPE = 3
403
+ TARGETTYPE = 4
404
+ PAGERANKPARAMS = 5
403
405
 
404
406
  FIELDS = {
405
407
  EDGETYPE => {:type => ::Thrift::Types::STRING, :name => 'edgeType'},
406
408
  SEEDS => {:type => ::Thrift::Types::LIST, :name => 'seeds', :element => {:type => ::Thrift::Types::I64}},
409
+ SEEDTYPE => {:type => ::Thrift::Types::STRING, :name => 'seedType'},
410
+ TARGETTYPE => {:type => ::Thrift::Types::STRING, :name => 'targetType'},
407
411
  PAGERANKPARAMS => {:type => ::Thrift::Types::STRUCT, :name => 'pageRankParams', :class => ::Teapot::TempestDB::MonteCarloPageRankParams}
408
412
  }
409
413
 
@@ -104,7 +104,7 @@ module Teapot
104
104
  MAXINTERMEDIATENODEDEGREE = 3
105
105
  MINREPORTEDVISITS = 4
106
106
  MAXRESULTCOUNT = 5
107
- UNDIRECTGRAPH = 6
107
+ ALTERNATINGWALK = 6
108
108
 
109
109
  FIELDS = {
110
110
  NUMSTEPS => {:type => ::Thrift::Types::I32, :name => 'numSteps'},
@@ -112,7 +112,7 @@ module Teapot
112
112
  MAXINTERMEDIATENODEDEGREE => {:type => ::Thrift::Types::I32, :name => 'maxIntermediateNodeDegree', :default => 1000, :optional => true},
113
113
  MINREPORTEDVISITS => {:type => ::Thrift::Types::I32, :name => 'minReportedVisits', :optional => true},
114
114
  MAXRESULTCOUNT => {:type => ::Thrift::Types::I32, :name => 'maxResultCount', :optional => true},
115
- UNDIRECTGRAPH => {:type => ::Thrift::Types::BOOL, :name => 'undirectGraph', :default => false, :optional => true}
115
+ ALTERNATINGWALK => {:type => ::Thrift::Types::BOOL, :name => 'alternatingWalk', :default => true, :optional => true}
116
116
  }
117
117
 
118
118
  def struct_fields; FIELDS; end
data/lib/tempest_db.rb CHANGED
@@ -26,10 +26,18 @@ require 'base_thrift_client'
26
26
 
27
27
  module Teapot
28
28
  module TempestDB
29
- class TempestClient < Teapot::BaseThriftClient
29
+ class TempestThriftClient < Teapot::BaseThriftClient
30
30
  def init_executor(protocol)
31
31
  Teapot::TempestDB::TempestDBService::Client.new(protocol)
32
32
  end
33
+ end
34
+
35
+ class TempestClient
36
+ @thrift_client = nil
37
+
38
+ def initialize(server, port)
39
+ @thrift_client = Teapot::TempestDB::TempestThriftClient.new(server, port)
40
+ end
33
41
 
34
42
  def TempestClient.jsonToValue(json_attribute)
35
43
  if json_attribute[0] == '"'
@@ -46,28 +54,119 @@ module Teapot
46
54
  end
47
55
  end
48
56
 
49
- def getMultiNodeAttribute(graphName, nodeIds, attributeName)
50
- id_to_json = get_executor.getMultiNodeAttributeAsJSON(graphName, nodeIds, attributeName)
57
+ def get_multi_node_attribute(node_type, nodeIds, attribute_name)
58
+ id_to_json = @thrift_client.with_retries { |executor|
59
+ executor.getMultiNodeAttributeAsJSON(node_type, nodeIds, attribute_name)
60
+ }
51
61
  Hash[id_to_json.map{ |k,v| [k, TempestClient.jsonToValue(v)] }]
52
62
  end
53
63
 
54
- def getNodeAttribute(graphName, nodeId, attributeName)
55
- self.getMultiNodeAttribute(graphName, [nodeId], attributeName)[nodeId]
64
+ def get_node_attribute(node_type, nodeId, attribute_name)
65
+ self.get_multi_node_attribute(node_type, [nodeId], attribute_name)[nodeId]
56
66
  end
57
67
 
58
- def kStepOutNeighborsFiltered(edgeType, sourceId, k, sqlClause: "", degreeFilter: {}, alternating: true)
59
- get_executor.kStepOutNeighborsFiltered(edgeType, sourceId, k, sqlClause, degreeFilter, alternating)
68
+ def k_step_out_neighbors_filtered(edge_type, source_id, k, sql_clause: "", degree_filter: {}, alternating: true)
69
+ @thrift_client.with_retries { |executor|
70
+ executor.kStepOutNeighborsFiltered(edge_type, source_id, k, sql_clause, degree_filter, alternating)
71
+ }
72
+ end
73
+
74
+ def k_step_in_neighbors_filtered(edge_type, source_id, k, sql_clause: "", degree_filter: {}, alternating: true)
75
+ @thrift_client.with_retries { |executor|
76
+ executor.kStepInNeighborsFiltered(edge_type, source_id, k, sql_clause, degree_filter, alternating)
77
+ }
78
+ end
79
+
80
+ # Convenience method to return the unique node id satisfying a condition
81
+ def unique_node(node_type, sql_clause)
82
+ matching_nodes = @thrift_client.with_retries { |executor|
83
+ executor.nodes(node_type, sql_clause)
84
+ }
85
+ if matching_nodes.length != 1
86
+ raise "Error: clause '#{sql_clause}' had #{matching_nodes.length} results"
87
+ end
88
+ matching_nodes[0]
60
89
  end
61
- def kStepInNeighborsFiltered(edgeType, sourceId, k, sqlClause: "", degreeFilter: {}, alternating: true)
62
- get_executor.kStepInNeighborsFiltered(edgeType, sourceId, k, sqlClause, degreeFilter, alternating)
90
+
91
+
92
+ # TODO: For methods that only need to be included (for irb auto-complete) and converted from camelCase to
93
+ # snake_case, is there a simple way of automating this?
94
+ def out_degree(edge_type, id)
95
+ @thrift_client.with_retries { |executor|
96
+ executor.outDegree(edge_type, id)
97
+ }
98
+ end
99
+
100
+ def in_degree(edge_type, id)
101
+ @thrift_client.with_retries { |executor|
102
+ executor.inDegree(edge_type, id)
103
+ }
104
+ end
105
+
106
+ def out_neighbors(edge_type, id)
107
+ @thrift_client.with_retries { |executor|
108
+ executor.outNeighbors(edge_type, id)
109
+ }
110
+ end
111
+
112
+ def in_neighbors(edge_type, id)
113
+ @thrift_client.with_retries { |executor|
114
+ executor.inNeighbors(edge_type, id)
115
+ }
116
+ end
117
+
118
+ def out_neighbor(edge_type, id, i)
119
+ @thrift_client.with_retries { |executor|
120
+ executor.outNeighbor(edge_type, id, i)
121
+ }
122
+ end
123
+
124
+ def in_neighbor(edge_type, id, i)
125
+ @thrift_client.with_retries { |executor|
126
+ executor.inNeighbor(edge_type, id, i)
127
+ }
128
+ end
129
+
130
+ def max_node_id(edge_type)
131
+ @thrift_client.with_retries { |executor|
132
+ executor.maxNodeId(edge_type)
133
+ }
134
+ end
135
+
136
+ def node_count(edge_type)
137
+ @thrift_client.with_retries { |executor|
138
+ executor.nodeCount(edge_type)
139
+ }
140
+ end
141
+
142
+ def edge_count(edge_type)
143
+ @thrift_client.with_retries { |executor|
144
+ executor.edgeCount(edge_type)
145
+ }
146
+ end
147
+
148
+ def ppr_single_target(edge_type, seed_node_ids, target_node_id, bi_ppr_params)
149
+ @thrift_client.with_retries { |executor|
150
+ executor.pprSingleTarget(edge_type, seed_node_ids, target_node_id, bi_ppr_params)
151
+ }
152
+ end
153
+
154
+ def ppr(edge_type, seed_node_ids, seed_node_type, target_node_type, mc_ppr_params)
155
+ @thrift_client.with_retries { |executor|
156
+ executor.ppr(edge_type, seed_node_ids, seed_node_type, target_node_type, mc_ppr_params)
157
+ }
158
+ end
159
+
160
+ def nodes(node_type, sql_clause)
161
+ @thrift_client.with_retries { |executor|
162
+ executor.nodes(node_type, sql_clause)
163
+ }
63
164
  end
64
165
 
65
- # Delegate other methods to the thrift generated method
66
- # Note: for autocomplete and documentation, we could improve usability by listing methods
67
- # explicitly (as we do for python), but that would require manual changes whenever the thrift
68
- # api changes, so for ruby we automatically delegate all other methods.
69
- def method_missing(m, *args)
70
- get_executor.send m, *args
166
+ def add_edges(edge_type, ids1, ids2)
167
+ @thrift_client.with_retries { |executor|
168
+ executor.addEdges(edge_type, ids1, ids2)
169
+ }
71
170
  end
72
171
  end
73
172
  end
metadata CHANGED
@@ -1,8 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tempest_db
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.1
5
- prerelease:
4
+ version: 0.13.2
6
5
  platform: ruby
7
6
  authors:
8
7
  - Peter Lofgren
@@ -11,10 +10,10 @@ authors:
11
10
  autorequire:
12
11
  bindir: bin
13
12
  cert_chain: []
14
- date: 2016-11-18 00:00:00.000000000 Z
13
+ date: 2016-12-19 00:00:00.000000000 Z
15
14
  dependencies: []
16
15
  description: Client for Tempest Graph Database.
17
- email: peter@teapot.co
16
+ email: peterl@stripe.com
18
17
  executables: []
19
18
  extensions: []
20
19
  extra_rdoc_files: []
@@ -30,26 +29,26 @@ files:
30
29
  homepage: http://teapot.co
31
30
  licenses:
32
31
  - Apache 2
32
+ metadata: {}
33
33
  post_install_message:
34
34
  rdoc_options: []
35
35
  require_paths:
36
36
  - lib
37
37
  required_ruby_version: !ruby/object:Gem::Requirement
38
- none: false
39
38
  requirements:
40
- - - ! '>='
39
+ - - ">="
41
40
  - !ruby/object:Gem::Version
42
41
  version: '0'
43
42
  required_rubygems_version: !ruby/object:Gem::Requirement
44
- none: false
45
43
  requirements:
46
- - - ! '>='
44
+ - - ">="
47
45
  - !ruby/object:Gem::Version
48
46
  version: '0'
49
47
  requirements: []
50
48
  rubyforge_project:
51
- rubygems_version: 1.8.23
49
+ rubygems_version: 2.4.5.1
52
50
  signing_key:
53
- specification_version: 3
51
+ specification_version: 4
54
52
  summary: Client for Tempest Graph Database
55
53
  test_files: []
54
+ has_rdoc: