Mercurial > hg > ng2-query-ismi
comparison app/query.service.ts @ 20:34cd764e234b
make interfaces into classes. factor out NormalizationService.
author | casties |
---|---|
date | Fri, 22 Jan 2016 17:32:33 +0100 |
parents | d75224bb8147 |
children | 930fe7460f6b |
comparison
equal
deleted
inserted
replaced
19:d75224bb8147 | 20:34cd764e234b |
---|---|
10 @Injectable() | 10 @Injectable() |
11 export class QueryService { | 11 export class QueryService { |
12 | 12 |
13 //public neo4jBaseUrl = 'https://ismi-dev.mpiwg-berlin.mpg.de/neo4j-ismi/db/data'; | 13 //public neo4jBaseUrl = 'https://ismi-dev.mpiwg-berlin.mpg.de/neo4j-ismi/db/data'; |
14 public neo4jBaseUrl = 'http://localhost:7474/db/data'; | 14 public neo4jBaseUrl = 'http://localhost:7474/db/data'; |
15 public openMindBaseUrl = 'https://ismi-dev.mpiwg-berlin.mpg.de/om4-ismi/'; | 15 public neo4jAuthentication = {'user': 'neo4j', 'password': 'neo5j'}; |
16 //public openMindBaseUrl = 'http://localhost:18080/ismi-richfaces/'; | |
17 public excludedAttributes = {'type': true}; | 16 public excludedAttributes = {'type': true}; |
18 public invRelPrefix = '<- '; | 17 public invRelPrefix = '<- '; |
19 public state: QueryState; | 18 public state: QueryState; |
20 public ismiObjectTypes: any; | 19 public objectTypes: string[]; |
21 | 20 |
22 constructor(private _http: Http) { | 21 constructor(private _http: Http) { |
23 this.state = { | 22 // init query state |
24 'steps': [], | 23 this.state = new QueryState(); |
25 'resultCypherQuery': '', | |
26 'cypherQueryParams': {}, | |
27 'attributesCypherQuery': '', | |
28 'relationsCypherQuery': '', | |
29 'results': [], | |
30 'resultTypes': '', | |
31 'numResults': 0, | |
32 'resultInfo': '' | |
33 }; | |
34 } | 24 } |
35 | 25 |
36 setup() { | 26 setup() { |
37 this.setupIsmiObjectTypes(); | 27 this.setupObjectTypes(); |
38 } | 28 } |
39 | 29 |
40 getState() { | 30 getState() { |
41 return this.state; | 31 return this.state; |
42 } | 32 } |
43 | 33 |
44 getQueryModes(): QueryMode[] { | 34 getQueryModes(): QueryMode[] { |
45 return QUERY_MODES; | 35 return QUERY_MODES; |
46 } | 36 } |
47 | 37 |
38 /** | |
39 * return the first set of options for the given query mode. | |
40 */ | |
48 getQueryOptions(queryMode: QueryMode) { | 41 getQueryOptions(queryMode: QueryMode) { |
49 var options = []; | 42 var options = []; |
50 if (queryMode == null) return options; | 43 if (queryMode == null) return options; |
51 if (queryMode.id === 'type_is') { | 44 if (queryMode.id === 'type_is') { |
52 options = this.ismiObjectTypes; | 45 options = this.objectTypes; |
53 } else if (queryMode.id === 'relation_is') { | 46 } else if (queryMode.id === 'relation_is') { |
54 options = this.state.nextQueryRelations; | 47 options = this.state.nextQueryRelations; |
55 } else if (queryMode.id === 'att_contains') { | 48 } else if (queryMode.id === 'att_contains') { |
56 options = this.state.nextQueryAttributes; | 49 options = this.state.nextQueryAttributes; |
57 } else if (queryMode.id === 'att_contains_norm') { | 50 } else if (queryMode.id === 'att_contains_norm') { |
61 } | 54 } |
62 console.debug("getQueryOptions returns: ", options); | 55 console.debug("getQueryOptions returns: ", options); |
63 return options; | 56 return options; |
64 } | 57 } |
65 | 58 |
66 setupIsmiObjectTypes() { | 59 /** |
60 * fetch all object types from Neo4j and store in this.objectTypes. | |
61 */ | |
62 setupObjectTypes() { | |
67 var query = `MATCH (n) WITH DISTINCT labels(n) AS labels | 63 var query = `MATCH (n) WITH DISTINCT labels(n) AS labels |
68 UNWIND labels AS label | 64 UNWIND labels AS label |
69 RETURN DISTINCT label ORDER BY label`; | 65 RETURN DISTINCT label ORDER BY label`; |
70 | 66 |
71 var res = this.fetchCypherResults([query]); | 67 var res = this.fetchCypherResults([query]); |
72 res.subscribe( | 68 res.subscribe( |
73 data => { | 69 data => { |
74 console.debug("neo4j data=", data); | 70 console.debug("neo4j data=", data); |
75 this.ismiObjectTypes = data.results[0].data.map(elem => elem.row[0]).filter(elem => elem[0] != "_"); | 71 this.objectTypes = data.results[0].data.map(elem => elem.row[0]).filter(elem => elem[0] != "_"); |
76 console.debug("ismi types=", this.ismiObjectTypes); | 72 console.debug("object types=", this.objectTypes); |
77 }, | 73 }, |
78 err => console.error("neo4j error=", err), | 74 err => console.error("neo4j error=", err), |
79 () => console.debug('neo4j query Complete') | 75 () => console.debug('neo4j query Complete') |
80 ); | 76 ); |
81 } | 77 } |
82 | 78 |
79 /** | |
80 * Set the query step at index. | |
81 */ | |
83 setQueryStep(index: number, step: QueryStep) { | 82 setQueryStep(index: number, step: QueryStep) { |
84 this.state.steps[index] = step; | 83 this.state.steps[index] = step; |
85 this.createCypherQuery(); | 84 } |
86 } | 85 |
87 | 86 /** |
87 * Create the cypher queries for the current query state. | |
88 * | |
89 * Updates the queries for results, attributes and relations. | |
90 */ | |
88 createCypherQuery() { | 91 createCypherQuery() { |
89 var queryMatch = ''; | 92 var queryMatch = ''; |
90 var queryWhere = ''; | 93 var queryWhere = ''; |
91 var queryReturn = ''; | 94 var queryReturn = ''; |
92 var queryParams = {}; | 95 var queryParams = {}; |
94 var attributesQuery = ''; | 97 var attributesQuery = ''; |
95 var relationsQuery = ''; | 98 var relationsQuery = ''; |
96 var returnType = ''; | 99 var returnType = ''; |
97 var nIdx = 1; | 100 var nIdx = 1; |
98 this.state.steps.forEach((step, stepIdx) => { | 101 this.state.steps.forEach((step, stepIdx) => { |
102 var mode = step.mode.id; | |
103 var params = step.params; | |
104 | |
99 /* | 105 /* |
100 * step: object type is | 106 * step: object type is |
101 */ | 107 */ |
102 if (step.mode.id === 'type_is') { | 108 if (mode === 'type_is') { |
103 queryMatch = `MATCH (n${nIdx}:${step.objectType})`; | 109 queryMatch = `MATCH (n${nIdx}:${params.objectType})`; |
104 queryWhere = ''; | 110 queryWhere = ''; |
105 queryReturn = `RETURN n${nIdx}`; | 111 queryReturn = `RETURN n${nIdx}`; |
106 returnType = 'node'; | 112 returnType = 'node'; |
107 } | 113 } |
108 | 114 |
109 /* | 115 /* |
110 * step: relation type is | 116 * step: relation type is |
111 */ | 117 */ |
112 if (step.mode.id === 'relation_is') { | 118 if (mode === 'relation_is') { |
113 nIdx += 1; | 119 nIdx += 1; |
114 var rel = step.relationType; | 120 var rel = params.relationType; |
115 if (rel.indexOf(this.invRelPrefix) == 0) { | 121 if (rel.indexOf(this.invRelPrefix) == 0) { |
116 // inverse relation | 122 // inverse relation |
117 rel = rel.substr(this.invRelPrefix.length); | 123 rel = rel.substr(this.invRelPrefix.length); |
118 queryMatch += `<-[:${rel}]-(n${nIdx})`; | 124 queryMatch += `<-[:${rel}]-(n${nIdx})`; |
119 } else { | 125 } else { |
124 } | 130 } |
125 | 131 |
126 /* | 132 /* |
127 * step: attribute contains(_norm) | 133 * step: attribute contains(_norm) |
128 */ | 134 */ |
129 if (step.mode.id === 'att_contains' || step.mode.id === 'att_contains_norm') { | 135 if (mode === 'att_contains' || mode === 'att_contains_norm') { |
130 if (!queryWhere) { | 136 if (!queryWhere) { |
131 queryWhere = 'WHERE '; | 137 queryWhere = 'WHERE '; |
132 } else { | 138 } else { |
133 queryWhere += ' AND '; | 139 queryWhere += ' AND '; |
134 } | 140 } |
135 if (step.attribute === 'ismi_id') { | 141 if (params.attribute === 'ismi_id') { |
136 // ismi_id is integer | 142 // ismi_id is integer |
137 queryWhere += `n${nIdx}.ismi_id = {att_val${stepIdx}}`; | 143 queryWhere += `n${nIdx}.ismi_id = {att_val${stepIdx}}`; |
138 queryParams[`att_val${stepIdx}`] = parseInt(step.value, 10); | 144 queryParams[`att_val${stepIdx}`] = parseInt(params.value, 10); |
139 } else { | 145 } else { |
140 if (step.mode.id === 'att_contains_norm') { | 146 if (mode === 'att_contains_norm') { |
141 // match _n_attribute with normValue | 147 // match _n_attribute with normValue |
142 queryWhere += `lower(n${nIdx}._n_${step.attribute}) CONTAINS lower({att_val${stepIdx}})`; | 148 queryWhere += `lower(n${nIdx}._n_${params.attribute}) CONTAINS lower({att_val${stepIdx}})`; |
143 queryParams[`att_val${stepIdx}`] = step.normValue; | 149 queryParams[`att_val${stepIdx}`] = params.normValue; |
144 } else { | 150 } else { |
145 queryWhere += `lower(n${nIdx}.${step.attribute}) CONTAINS lower({att_val${stepIdx}})`; | 151 queryWhere += `lower(n${nIdx}.${params.attribute}) CONTAINS lower({att_val${stepIdx}})`; |
146 queryParams[`att_val${stepIdx}`] = step.value; | 152 queryParams[`att_val${stepIdx}`] = params.value; |
147 } | 153 } |
148 } | 154 } |
149 } | 155 } |
150 | 156 |
151 /* | 157 /* |
152 * step: attribute number range | 158 * step: attribute number range |
153 */ | 159 */ |
154 if (step.mode.id === 'att_num_range') { | 160 if (mode === 'att_num_range') { |
155 if (!queryWhere) { | 161 if (!queryWhere) { |
156 queryWhere = 'WHERE '; | 162 queryWhere = 'WHERE '; |
157 } else { | 163 } else { |
158 queryWhere += ' AND '; | 164 queryWhere += ' AND '; |
159 } | 165 } |
160 queryWhere += `toint(n${nIdx}.${step.attribute}) >= toint({att_nlo${stepIdx}})` | 166 queryWhere += `toint(n${nIdx}.${params.attribute}) >= toint({att_nlo${stepIdx}})` |
161 + ` AND toint(n${nIdx}.${step.attribute}) <= toint({att_nhi${stepIdx}})`; | 167 + ` AND toint(n${nIdx}.${params.attribute}) <= toint({att_nhi${stepIdx}})`; |
162 queryParams[`att_nlo${stepIdx}`] = step.numLo; | 168 queryParams[`att_nlo${stepIdx}`] = params.numLo; |
163 queryParams[`att_nhi${stepIdx}`] = step.numHi; | 169 queryParams[`att_nhi${stepIdx}`] = params.numHi; |
164 } | 170 } |
165 | 171 |
166 }); | 172 }); |
167 // compose query | 173 // compose query |
168 resultQuery = queryMatch + '\n' + queryWhere + '\n' + queryReturn; | 174 resultQuery = queryMatch + '\n' + queryWhere + '\n' + queryReturn; |
176 this.state.attributesCypherQuery = attributesQuery; | 182 this.state.attributesCypherQuery = attributesQuery; |
177 this.state.relationsCypherQuery = relationsQuery; | 183 this.state.relationsCypherQuery = relationsQuery; |
178 this.state.resultTypes = returnType; | 184 this.state.resultTypes = returnType; |
179 } | 185 } |
180 | 186 |
187 /** | |
188 * Create and run the cypher queries for the current query state. | |
189 * | |
190 * Updates the results and nextQuery attributes and relations. | |
191 */ | |
181 updateQuery() { | 192 updateQuery() { |
182 this.createCypherQuery(); | 193 this.createCypherQuery(); |
183 this.state.resultInfo = 'loading...'; | 194 this.state.resultInfo = 'loading...'; |
184 /* | 195 /* |
185 * run query for result table | 196 * run query for result table |
244 err => console.error("neo4j result error=", err), | 255 err => console.error("neo4j result error=", err), |
245 () => console.debug('neo4j result query Complete') | 256 () => console.debug('neo4j result query Complete') |
246 ); | 257 ); |
247 } | 258 } |
248 | 259 |
260 /** | |
261 * Run the given queries on the Neo4J server. | |
262 * | |
263 * Returns an Observable with the results. | |
264 */ | |
249 fetchCypherResults(queries: string[], params=[{}]) { | 265 fetchCypherResults(queries: string[], params=[{}]) { |
250 console.debug("fetching cypher queries: ", queries); | 266 console.debug("fetching cypher queries: ", queries); |
251 var headers = new Headers(); | 267 var headers = new Headers(); |
252 headers.append('Authorization', 'Basic ' + btoa('neo4j' + ':' + 'neo5j')); | 268 var auth = this.neo4jAuthentication; |
269 headers.append('Authorization', 'Basic ' + btoa(`${auth.user}:${auth.password}`)); | |
253 headers.append('Content-Type', 'application/json'); | 270 headers.append('Content-Type', 'application/json'); |
254 headers.append('Accept', 'application/json'); | 271 headers.append('Accept', 'application/json'); |
255 // put headers in options | 272 // put headers in options |
256 var opts = {'headers': headers}; | 273 var opts = {'headers': headers}; |
257 // unpack queries into statements | 274 // unpack queries into statements |
266 .map(res => res.json()); | 283 .map(res => res.json()); |
267 // return Observable | 284 // return Observable |
268 return resp; | 285 return resp; |
269 } | 286 } |
270 | 287 |
271 fetchNormalizedString(text: string) { | |
272 console.debug("fetching normalized string: ", text); | |
273 var headers = new Headers(); | |
274 headers.append('Accept', 'application/json'); | |
275 // put headers in options | |
276 var opts = {'headers': headers}; | |
277 // make get request asynchronously | |
278 var url = this.openMindBaseUrl+'jsonInterface?method=normalize_string&type=arabic_translit&text='; | |
279 url += text; | |
280 var resp = this._http.get(url, opts) | |
281 // filter result as JSON | |
282 .map(res => res.json()); | |
283 // return Observable | |
284 return resp; | |
285 } | |
286 } | 288 } |