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 }