From 2e4ebc12bfd26e5a748480e2e57d859702ac655e Mon Sep 17 00:00:00 2001 From: IsolatedSushi <simen.vanherpt@gmail.com> Date: Mon, 15 Feb 2021 14:05:13 +0100 Subject: [PATCH] Further semantic knn --- backend/grpcKNN/knnServer.py | 81 +++++++++----- backend/grpcKNN/knn_pb2.py | 105 ++++-------------- backend/grpcKNN/knn_pb2_grpc.py | 53 ++------- backend/grpcKNN/protos/v3/knn.proto | 13 +-- backend/grpcKNN/requirements.txt | 3 +- backend/webSocketGateway/protos/v3/knn.proto | 13 +-- .../webSocketGateway/src/webSocketGateway.js | 56 ++++++---- 7 files changed, 134 insertions(+), 190 deletions(-) diff --git a/backend/grpcKNN/knnServer.py b/backend/grpcKNN/knnServer.py index b192169..ef86cbd 100644 --- a/backend/grpcKNN/knnServer.py +++ b/backend/grpcKNN/knnServer.py @@ -4,6 +4,8 @@ import knn_pb2_grpc as rpc import faiss import knn_pb2 as knn import numpy as np +import re +import operator from tabulate import tabulate class Data(): @@ -52,24 +54,53 @@ class KNNService(rpc.KNNServicer): return knn.ID(id=str(clientID)) #Do simple linalg expression with 3 vector, improve later - def getKNNSemantic(self,request,context): - dataObject = self.clientList[self.metaToID(context)] - - words = [x.lower() for x in request.words] - if words[0] not in dataObject.wordToID or words[1] not in dataObject.wordToID or words[2] not in dataObject.wordToID: - print("a word is not in the set") - return - vector1 = dataObject.allData[dataObject.wordToID[words[0]]] - vector2 = dataObject.allData[dataObject.wordToID[words[1]]] - vector3 = dataObject.allData[dataObject.wordToID[words[2]]] - - linVector = np.array(vector1) - np.array(vector2) + np.array(vector3) - neighbours = self.knnVector(linVector,10,dataObject) - return neighbours + def getKNNRequest(self,request,context): + ops = { "+": operator.add, "-": operator.sub } + try: + dataObject = self.clientList[self.metaToID(context)] + print("Words ",request.words) + strippedWord = "".join(request.words.split()) + wordList = re.split('-|\+',strippedWord) + print("WordList",wordList) + + wordList = [x.lower() for x in wordList] + for word in wordList: + if word not in dataObject.wordToID: + print("Word", word, " not in the set") + return knn.Neighbours() + + orderedOperators = ''.join(c for c in request.words if c in ["-","+"]) + print("ordererdOperators",orderedOperators) + print("test",dataObject.wordToID[wordList[0]]) + firstID = dataObject.wordToID[wordList[0]] + resultedVector = np.array(dataObject.allData[firstID]) + print("resultedVector",resultedVector) + + for i in range(1,len(wordList)): + print("i",i) + nextID = dataObject.wordToID[wordList[i]] + resultedVector = ops[orderedOperators[i]](resultedVector, np.array(dataObject.allData[nextID])) + + + + + # if words[0] not in dataObject.wordToID or words[1] not in dataObject.wordToID or words[2] not in dataObject.wordToID: + # print("a word is not in the set") + # return + # vector1 = dataObject.allData[dataObject.wordToID[words[0]]] + # vector2 = dataObject.allData[dataObject.wordToID[words[1]]] + # vector3 = dataObject.allData[dataObject.wordToID[words[2]]] + + # linVector = np.array(vector1) - np.array(vector2) + np.array(vector3) + neighbours = self.knnVector(resultedVector,10,dataObject) + return neighbours + except Exception as e: + print(e) #Perform actual KNN def knnVector(self,vector,k,dataObject): + print("vector",vector) D, I = dataObject.index.search(np.asarray([vector]), k) words = [dataObject.ids[x] for x in I[0]] distances = D[0] @@ -77,19 +108,19 @@ class KNNService(rpc.KNNServicer): neighbours = knn.Neighbours(rows=returnRows) return neighbours - def getKNNSingle(self, request, context): - dataObject = self.clientList[self.metaToID(context)] - word = request.word.lower() - print("Received request",word) + # def getKNNSingle(self, request, context): + # dataObject = self.clientList[self.metaToID(context)] + # word = request.word.lower() + # print("Received request",word) - if word not in dataObject.wordToID: - print(word,"not in the set (yet)") - return knn.Neighbours() + # if word not in dataObject.wordToID: + # print(word,"not in the set (yet)") + # return knn.Neighbours() - wordIndex = dataObject.wordToID[word] - vector = dataObject.allData[wordIndex] - neighbours = self.knnVector(vector,10,dataObject) - return neighbours + # wordIndex = dataObject.wordToID[word] + # vector = dataObject.allData[wordIndex] + # neighbours = self.knnVector(vector,10,dataObject) + # return neighbours def sendProjectionPoints(self, request_iterator, context): print("Connected") diff --git a/backend/grpcKNN/knn_pb2.py b/backend/grpcKNN/knn_pb2.py index 282e958..4f830a6 100644 --- a/backend/grpcKNN/knn_pb2.py +++ b/backend/grpcKNN/knn_pb2.py @@ -20,7 +20,7 @@ DESCRIPTOR = _descriptor.FileDescriptor( syntax='proto3', serialized_options=b'\n\017nl.uuvig.proveeB\022ProveProjectorGRCPP\001\242\002\006PROVEE', create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\tknn.proto\x12\x06provee\x1a\x1bgoogle/protobuf/empty.proto\"\x10\n\x02ID\x12\n\n\x02id\x18\x01 \x01(\t\"+\n\x10knnSingleRequest\x12\t\n\x01k\x18\x01 \x01(\x05\x12\x0c\n\x04word\x18\x02 \x01(\t\".\n\x12knnSemanticRequest\x12\t\n\x01k\x18\x01 \x01(\x05\x12\r\n\x05words\x18\x02 \x03(\t\"\'\n\nNeighbours\x12\x19\n\x04rows\x18\x01 \x03(\x0b\x32\x0b.provee.Row\"#\n\x03Row\x12\n\n\x02id\x18\x01 \x01(\t\x12\x10\n\x08\x64istance\x18\x02 \x01(\x02\"2\n\x0eTrainingSetRow\x12\n\n\x02id\x18\x01 \x01(\t\x12\x14\n\x08hdvector\x18\x02 \x03(\x01\x42\x02\x10\x01\x32\x8e\x02\n\x03KNN\x12J\n\x14sendProjectionPoints\x12\x16.provee.TrainingSetRow\x1a\x16.google.protobuf.Empty\"\x00(\x01\x12>\n\x0cgetKNNSingle\x12\x18.provee.knnSingleRequest\x1a\x12.provee.Neighbours\"\x00\x12\x42\n\x0egetKNNSemantic\x12\x1a.provee.knnSemanticRequest\x1a\x12.provee.Neighbours\"\x00\x12\x37\n\x0fgetIDfromServer\x12\x16.google.protobuf.Empty\x1a\n.provee.ID\"\x00\x42\x30\n\x0fnl.uuvig.proveeB\x12ProveProjectorGRCPP\x01\xa2\x02\x06PROVEEb\x06proto3' + serialized_pb=b'\n\tknn.proto\x12\x06provee\x1a\x1bgoogle/protobuf/empty.proto\"\x10\n\x02ID\x12\n\n\x02id\x18\x01 \x01(\t\"&\n\nknnRequest\x12\t\n\x01k\x18\x01 \x01(\x05\x12\r\n\x05words\x18\x02 \x01(\t\"\'\n\nNeighbours\x12\x19\n\x04rows\x18\x01 \x03(\x0b\x32\x0b.provee.Row\"#\n\x03Row\x12\n\n\x02id\x18\x01 \x01(\t\x12\x10\n\x08\x64istance\x18\x02 \x01(\x02\"2\n\x0eTrainingSetRow\x12\n\n\x02id\x18\x01 \x01(\t\x12\x14\n\x08hdvector\x18\x02 \x03(\x01\x42\x02\x10\x01\x32\xc5\x01\n\x03KNN\x12J\n\x14sendProjectionPoints\x12\x16.provee.TrainingSetRow\x1a\x16.google.protobuf.Empty\"\x00(\x01\x12\x39\n\rgetKNNRequest\x12\x12.provee.knnRequest\x1a\x12.provee.Neighbours\"\x00\x12\x37\n\x0fgetIDfromServer\x12\x16.google.protobuf.Empty\x1a\n.provee.ID\"\x00\x42\x30\n\x0fnl.uuvig.proveeB\x12ProveProjectorGRCPP\x01\xa2\x02\x06PROVEEb\x06proto3' , dependencies=[google_dot_protobuf_dot_empty__pb2.DESCRIPTOR,]) @@ -59,23 +59,23 @@ _ID = _descriptor.Descriptor( ) -_KNNSINGLEREQUEST = _descriptor.Descriptor( - name='knnSingleRequest', - full_name='provee.knnSingleRequest', +_KNNREQUEST = _descriptor.Descriptor( + name='knnRequest', + full_name='provee.knnRequest', filename=None, file=DESCRIPTOR, containing_type=None, create_key=_descriptor._internal_create_key, fields=[ _descriptor.FieldDescriptor( - name='k', full_name='provee.knnSingleRequest.k', index=0, + name='k', full_name='provee.knnRequest.k', index=0, number=1, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( - name='word', full_name='provee.knnSingleRequest.word', index=1, + name='words', full_name='provee.knnRequest.words', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, @@ -94,46 +94,7 @@ _KNNSINGLEREQUEST = _descriptor.Descriptor( oneofs=[ ], serialized_start=68, - serialized_end=111, -) - - -_KNNSEMANTICREQUEST = _descriptor.Descriptor( - name='knnSemanticRequest', - full_name='provee.knnSemanticRequest', - filename=None, - file=DESCRIPTOR, - containing_type=None, - create_key=_descriptor._internal_create_key, - fields=[ - _descriptor.FieldDescriptor( - name='k', full_name='provee.knnSemanticRequest.k', index=0, - number=1, type=5, cpp_type=1, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='words', full_name='provee.knnSemanticRequest.words', index=1, - number=2, type=9, cpp_type=9, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=113, - serialized_end=159, + serialized_end=106, ) @@ -164,8 +125,8 @@ _NEIGHBOURS = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=161, - serialized_end=200, + serialized_start=108, + serialized_end=147, ) @@ -203,8 +164,8 @@ _ROW = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=202, - serialized_end=237, + serialized_start=149, + serialized_end=184, ) @@ -242,14 +203,13 @@ _TRAININGSETROW = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=239, - serialized_end=289, + serialized_start=186, + serialized_end=236, ) _NEIGHBOURS.fields_by_name['rows'].message_type = _ROW DESCRIPTOR.message_types_by_name['ID'] = _ID -DESCRIPTOR.message_types_by_name['knnSingleRequest'] = _KNNSINGLEREQUEST -DESCRIPTOR.message_types_by_name['knnSemanticRequest'] = _KNNSEMANTICREQUEST +DESCRIPTOR.message_types_by_name['knnRequest'] = _KNNREQUEST DESCRIPTOR.message_types_by_name['Neighbours'] = _NEIGHBOURS DESCRIPTOR.message_types_by_name['Row'] = _ROW DESCRIPTOR.message_types_by_name['TrainingSetRow'] = _TRAININGSETROW @@ -262,19 +222,12 @@ ID = _reflection.GeneratedProtocolMessageType('ID', (_message.Message,), { }) _sym_db.RegisterMessage(ID) -knnSingleRequest = _reflection.GeneratedProtocolMessageType('knnSingleRequest', (_message.Message,), { - 'DESCRIPTOR' : _KNNSINGLEREQUEST, - '__module__' : 'knn_pb2' - # @@protoc_insertion_point(class_scope:provee.knnSingleRequest) - }) -_sym_db.RegisterMessage(knnSingleRequest) - -knnSemanticRequest = _reflection.GeneratedProtocolMessageType('knnSemanticRequest', (_message.Message,), { - 'DESCRIPTOR' : _KNNSEMANTICREQUEST, +knnRequest = _reflection.GeneratedProtocolMessageType('knnRequest', (_message.Message,), { + 'DESCRIPTOR' : _KNNREQUEST, '__module__' : 'knn_pb2' - # @@protoc_insertion_point(class_scope:provee.knnSemanticRequest) + # @@protoc_insertion_point(class_scope:provee.knnRequest) }) -_sym_db.RegisterMessage(knnSemanticRequest) +_sym_db.RegisterMessage(knnRequest) Neighbours = _reflection.GeneratedProtocolMessageType('Neighbours', (_message.Message,), { 'DESCRIPTOR' : _NEIGHBOURS, @@ -308,8 +261,8 @@ _KNN = _descriptor.ServiceDescriptor( index=0, serialized_options=None, create_key=_descriptor._internal_create_key, - serialized_start=292, - serialized_end=562, + serialized_start=239, + serialized_end=436, methods=[ _descriptor.MethodDescriptor( name='sendProjectionPoints', @@ -322,21 +275,11 @@ _KNN = _descriptor.ServiceDescriptor( create_key=_descriptor._internal_create_key, ), _descriptor.MethodDescriptor( - name='getKNNSingle', - full_name='provee.KNN.getKNNSingle', + name='getKNNRequest', + full_name='provee.KNN.getKNNRequest', index=1, containing_service=None, - input_type=_KNNSINGLEREQUEST, - output_type=_NEIGHBOURS, - serialized_options=None, - create_key=_descriptor._internal_create_key, - ), - _descriptor.MethodDescriptor( - name='getKNNSemantic', - full_name='provee.KNN.getKNNSemantic', - index=2, - containing_service=None, - input_type=_KNNSEMANTICREQUEST, + input_type=_KNNREQUEST, output_type=_NEIGHBOURS, serialized_options=None, create_key=_descriptor._internal_create_key, @@ -344,7 +287,7 @@ _KNN = _descriptor.ServiceDescriptor( _descriptor.MethodDescriptor( name='getIDfromServer', full_name='provee.KNN.getIDfromServer', - index=3, + index=2, containing_service=None, input_type=google_dot_protobuf_dot_empty__pb2._EMPTY, output_type=_ID, diff --git a/backend/grpcKNN/knn_pb2_grpc.py b/backend/grpcKNN/knn_pb2_grpc.py index deb6ac3..84f4bb8 100644 --- a/backend/grpcKNN/knn_pb2_grpc.py +++ b/backend/grpcKNN/knn_pb2_grpc.py @@ -21,14 +21,9 @@ class KNNStub(object): request_serializer=knn__pb2.TrainingSetRow.SerializeToString, response_deserializer=google_dot_protobuf_dot_empty__pb2.Empty.FromString, ) - self.getKNNSingle = channel.unary_unary( - '/provee.KNN/getKNNSingle', - request_serializer=knn__pb2.knnSingleRequest.SerializeToString, - response_deserializer=knn__pb2.Neighbours.FromString, - ) - self.getKNNSemantic = channel.unary_unary( - '/provee.KNN/getKNNSemantic', - request_serializer=knn__pb2.knnSemanticRequest.SerializeToString, + self.getKNNRequest = channel.unary_unary( + '/provee.KNN/getKNNRequest', + request_serializer=knn__pb2.knnRequest.SerializeToString, response_deserializer=knn__pb2.Neighbours.FromString, ) self.getIDfromServer = channel.unary_unary( @@ -48,13 +43,7 @@ class KNNServicer(object): context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') - def getKNNSingle(self, request, context): - """Missing associated documentation comment in .proto file.""" - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def getKNNSemantic(self, request, context): + def getKNNRequest(self, request, context): """Missing associated documentation comment in .proto file.""" context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -74,14 +63,9 @@ def add_KNNServicer_to_server(servicer, server): request_deserializer=knn__pb2.TrainingSetRow.FromString, response_serializer=google_dot_protobuf_dot_empty__pb2.Empty.SerializeToString, ), - 'getKNNSingle': grpc.unary_unary_rpc_method_handler( - servicer.getKNNSingle, - request_deserializer=knn__pb2.knnSingleRequest.FromString, - response_serializer=knn__pb2.Neighbours.SerializeToString, - ), - 'getKNNSemantic': grpc.unary_unary_rpc_method_handler( - servicer.getKNNSemantic, - request_deserializer=knn__pb2.knnSemanticRequest.FromString, + 'getKNNRequest': grpc.unary_unary_rpc_method_handler( + servicer.getKNNRequest, + request_deserializer=knn__pb2.knnRequest.FromString, response_serializer=knn__pb2.Neighbours.SerializeToString, ), 'getIDfromServer': grpc.unary_unary_rpc_method_handler( @@ -118,24 +102,7 @@ class KNN(object): insecure, call_credentials, compression, wait_for_ready, timeout, metadata) @staticmethod - def getKNNSingle(request, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.unary_unary(request, target, '/provee.KNN/getKNNSingle', - knn__pb2.knnSingleRequest.SerializeToString, - knn__pb2.Neighbours.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) - - @staticmethod - def getKNNSemantic(request, + def getKNNRequest(request, target, options=(), channel_credentials=None, @@ -145,8 +112,8 @@ class KNN(object): wait_for_ready=None, timeout=None, metadata=None): - return grpc.experimental.unary_unary(request, target, '/provee.KNN/getKNNSemantic', - knn__pb2.knnSemanticRequest.SerializeToString, + return grpc.experimental.unary_unary(request, target, '/provee.KNN/getKNNRequest', + knn__pb2.knnRequest.SerializeToString, knn__pb2.Neighbours.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata) diff --git a/backend/grpcKNN/protos/v3/knn.proto b/backend/grpcKNN/protos/v3/knn.proto index 13e72de..2bdc51b 100644 --- a/backend/grpcKNN/protos/v3/knn.proto +++ b/backend/grpcKNN/protos/v3/knn.proto @@ -15,8 +15,7 @@ service KNN { rpc sendProjectionPoints(stream TrainingSetRow) returns (google.protobuf.Empty) {} - rpc getKNNSingle(knnSingleRequest) returns (Neighbours) {} - rpc getKNNSemantic(knnSemanticRequest) returns (Neighbours) {} + rpc getKNNRequest(knnRequest) returns (Neighbours) {} rpc getIDfromServer(google.protobuf.Empty) returns (ID) {} } @@ -24,15 +23,9 @@ message ID{ string id = 1; } -// Points are represented as x-y pairs -message knnSingleRequest{ +message knnRequest{ int32 k = 1; - string word = 2; -} - -message knnSemanticRequest{ - int32 k = 1; - repeated string words = 2; + string words = 2; } message Neighbours { diff --git a/backend/grpcKNN/requirements.txt b/backend/grpcKNN/requirements.txt index a6bd7f3..d5d065e 100644 --- a/backend/grpcKNN/requirements.txt +++ b/backend/grpcKNN/requirements.txt @@ -4,4 +4,5 @@ protobuf==3.14.0 six==1.15.0 faiss-cpu==1.7.0 numpy==1.19.2 -tabulate==0.8.7 \ No newline at end of file +tabulate==0.8.7 +regex==2020.7.14 \ No newline at end of file diff --git a/backend/webSocketGateway/protos/v3/knn.proto b/backend/webSocketGateway/protos/v3/knn.proto index 13e72de..2bdc51b 100644 --- a/backend/webSocketGateway/protos/v3/knn.proto +++ b/backend/webSocketGateway/protos/v3/knn.proto @@ -15,8 +15,7 @@ service KNN { rpc sendProjectionPoints(stream TrainingSetRow) returns (google.protobuf.Empty) {} - rpc getKNNSingle(knnSingleRequest) returns (Neighbours) {} - rpc getKNNSemantic(knnSemanticRequest) returns (Neighbours) {} + rpc getKNNRequest(knnRequest) returns (Neighbours) {} rpc getIDfromServer(google.protobuf.Empty) returns (ID) {} } @@ -24,15 +23,9 @@ message ID{ string id = 1; } -// Points are represented as x-y pairs -message knnSingleRequest{ +message knnRequest{ int32 k = 1; - string word = 2; -} - -message knnSemanticRequest{ - int32 k = 1; - repeated string words = 2; + string words = 2; } message Neighbours { diff --git a/backend/webSocketGateway/src/webSocketGateway.js b/backend/webSocketGateway/src/webSocketGateway.js index e0e059d..2ba6591 100644 --- a/backend/webSocketGateway/src/webSocketGateway.js +++ b/backend/webSocketGateway/src/webSocketGateway.js @@ -9,6 +9,8 @@ const webSocketPort = 9898 var projectorTarget = process.env.PROJECTOR_TARGET ||'127.0.0.1:50051'; //var target = "proveeprojectorservice:50051" var knnTarget = process.env.KNN_TARGET || '127.0.0.1:50052'; //"proveeknnservice:50052" const wsServer = new WebSocket.Server({ host: webSocketHost, port: webSocketPort }); + + console.log("Projector target " +projectorTarget); console.log("KNN target: " + knnTarget) var projectorPackage = getGRPCPackage( __dirname + '/../protos/v3/projector.proto'); @@ -119,27 +121,41 @@ function sendError(ws,message){ } -function KNNNeighbourRequest(connection,words,k){ +function KNNNeighbourRequest(connection,words,k){ + console.log("Requesting " + words) const meta = new grpc.Metadata(); meta.add('id',connection.knnConn.id); - if(words.length == 1){ - connection.knnConn.client.getKNNSingle({k: k, word: words[0]},meta, function(err,response){ - console.log("got response"); - console.log(err); - sendNeighbour(response,connection.ws); - }) - } - else if(words.length == 3){ - connection.knnConn.client.getKNNSemantic({k:k,words: words},meta,function(err,response){ - console.log("got response"); - console.log(err); - sendNeighbour(response,connection.ws); - }) - } - else{ - console.log("No valid request: " + words) - sendError(connection.ws,"No valid request: " + words) - } + connection.knnConn.client.getKNNRequest({k:k,words: words},meta,function(err,response){ + if(response){ + console.log("got response"); + sendNeighbour(response,connection.ws); + } + else{ + + } + + console.log(err); + }); + + + // if(words.length == 1){ + // connection.knnConn.client.getKNNSingle({k: k, word: words[0]},meta, function(err,response){ + // console.log("got response"); + // console.log(err); + // sendNeighbour(response,connection.ws); + // }) + // } + // else if(words.length == 3){ + // connection.knnConn.client.getKNNSemantic({k:k,words: words},meta,function(err,response){ + // console.log("got response"); + // console.log(err); + // sendNeighbour(response,connection.ws); + // }) + // } + // else{ + // console.log("No valid request: " + words) + // sendError(connection.ws,"No valid request: " + words) + // } } //Parse the message from browser function parseMessage(message, connection) { @@ -157,7 +173,7 @@ function parseMessage(message, connection) { break; case "getKNNNeighbours": var k = parseInt(jsonMessage["amount"]); - var words = jsonMessage["word"].split(','); + var words = jsonMessage["word"] if(!connection.knnConn){ console.log("No KNN microservice"); -- GitLab