@@ -59,6 +59,11 @@ public class FragnetSearchRouteBuilder extends AbstractFragnetSearchRouteBuilder
5959 .help ("Total number of molecule search requests" )
6060 .register ();
6161
62+ private final Counter fragmentSearchRequestsTotal = Counter .build ()
63+ .name ("requests_fragment_total" )
64+ .help ("Total number of fragment search requests" )
65+ .register ();
66+
6267 private final Counter neighbourhoodSearchRequestsTotal = Counter .build ()
6368 .name ("requests_neighbourhood_total" )
6469 .help ("Total number of neighbourhood search requests" )
@@ -84,6 +89,11 @@ public class FragnetSearchRouteBuilder extends AbstractFragnetSearchRouteBuilder
8489 .help ("Total duration of molecule Neo4j cypher query" )
8590 .register ();
8691
92+ private final Counter fragmentSearchNeo4jSearchDuration = Counter .build ()
93+ .name ("duration_fragment_neo4j_ns" )
94+ .help ("Total duration of fragment Neo4j cypher query" )
95+ .register ();
96+
8797 private final Counter neighbourhoodSearchNeo4jSearchDuration = Counter .build ()
8898 .name ("duration_neighbourhood_neo4j_ns" )
8999 .help ("Total duration of neighbourhood Neo4j cypher query" )
@@ -104,6 +114,16 @@ public class FragnetSearchRouteBuilder extends AbstractFragnetSearchRouteBuilder
104114 .help ("Total number of molecule search misses" )
105115 .register ();
106116
117+ private final Counter fragmentSearchMissesTotal = Counter .build ()
118+ .name ("results_fragment_misses_molecules" )
119+ .help ("Total number of fragment search misses" )
120+ .register ();
121+
122+ private final Counter fragmentSearchMoleculesTotal = Counter .build ()
123+ .name ("results_fragments_molecules" )
124+ .help ("Total number of fragment search fragments" )
125+ .register ();
126+
107127 private final Counter neighbourhoodSearchHitsTotal = Counter .build ()
108128 .name ("results_neighbourhood_hits_molecules" )
109129 .help ("Total number of molecules found for neighbourhood search" )
@@ -191,7 +211,7 @@ public void configure() throws Exception {
191211 executeMoleculeQuery (exch );
192212 })
193213 .endRest ()
194- .post ("molecule/ " ).description ("Molecule search" )
214+ .post ("molecule" ).description ("Molecule search" )
195215 .bindingMode (RestBindingMode .off )
196216 .param ().name ("molfile" ).type (RestParamType .body ).description ("Molfile query" ).endParam ()
197217 .produces ("application/json" )
@@ -201,6 +221,27 @@ public void configure() throws Exception {
201221 })
202222 .marshal ().json (JsonLibrary .Jackson )
203223 .endRest ()
224+ // Is this molecule part of the fragment network
225+ // example:
226+ // curl "$FRAGNET_SERVER/fragnet-search/rest/v2/search/molecule/OC(Cn1ccnn1)C1CC1"
227+ .get ("fragments/{smiles}" ).description ("Find fragments of a molecule" )
228+ .param ().name ("smiles" ).type (RestParamType .path ).description ("SMILES query" ).endParam ()
229+ .produces ("application/json" )
230+ .route ()
231+ .process ((Exchange exch ) -> {
232+ executeFragmentQuery (exch );
233+ })
234+ .endRest ()
235+ .post ("fragments" ).description ("MFind fragments of a molecule" )
236+ .bindingMode (RestBindingMode .off )
237+ .param ().name ("molfile" ).type (RestParamType .body ).description ("Molfile query" ).endParam ()
238+ .produces ("application/json" )
239+ .route ()
240+ .process ((Exchange exch ) -> {
241+ executeFragmentQuery (exch );
242+ })
243+ .marshal ().json (JsonLibrary .Jackson )
244+ .endRest ()
204245 // example:
205246 // curl "$FRAGNET_SERVER/fragnet-search/rest/v2/search/neighbourhood/c1ccc%28Nc2nc3ccccc3o2%29cc1?hac=3&rac=1&hops=2&calcs=LOGP,SIM_RDKIT_TANIMOTO"
206247 .get ("neighbourhood/{smiles}" ).description ("Neighbourhood search" )
@@ -568,6 +609,23 @@ void executeExpansionMultiQuery(Exchange exch) {
568609 }
569610 }
570611
612+ private String [] fetchSmilesOrMolfile (Message message ) {
613+ String queryMol = null ;
614+ String mimeType = message .getHeader (Exchange .CONTENT_TYPE , String .class );
615+ LOG .info ("mime-type is " + mimeType );
616+ if (mimeType == null ) {
617+ mimeType = Constants .MIME_TYPE_SMILES ;
618+ }
619+ if (Constants .MIME_TYPE_SMILES .equals (mimeType )) {
620+ queryMol = message .getHeader ("smiles" , String .class );
621+ } else if (Constants .MIME_TYPE_MOLFILE .equals (mimeType )) {
622+ queryMol = message .getBody (String .class );
623+ } else {
624+ throw new IllegalStateException ("Only support SMILES using GET or molfile using POST" );
625+ }
626+ return new String [] {queryMol , mimeType };
627+ }
628+
571629 void executeMoleculeQuery (Exchange exch ) {
572630
573631 LOG .info ("Executing executeMoleculeQuery" );
@@ -580,19 +638,9 @@ void executeMoleculeQuery(Exchange exch) {
580638 String username = getUsername (exch );
581639
582640 try {
583- String queryMol = null ;
584- String mimeType = message .getHeader (Exchange .CONTENT_TYPE , String .class );
585- LOG .info ("mime-type is " + mimeType );
586- if (mimeType == null ) {
587- mimeType = Constants .MIME_TYPE_SMILES ;
588- }
589- if (Constants .MIME_TYPE_SMILES .equals (mimeType )) {
590- queryMol = message .getHeader ("smiles" , String .class );
591- } else if (Constants .MIME_TYPE_MOLFILE .equals (mimeType )) {
592- queryMol = message .getBody (String .class );
593- } else {
594- throw new IllegalStateException ("Only support SMILES using GET or molfile using POST" );
595- }
641+ String [] data = fetchSmilesOrMolfile (message );
642+ String queryMol = data [0 ];
643+ String mimeType = data [1 ];
596644
597645 if (queryMol == null || queryMol .isEmpty ()) {
598646 throw new IllegalArgumentException ("Query molecule must be specified" );
@@ -630,6 +678,59 @@ void executeMoleculeQuery(Exchange exch) {
630678 }
631679 }
632680
681+ void executeFragmentQuery (Exchange exch ) {
682+ LOG .info ("Executing executeMoleculeQuery" );
683+
684+ fragmentSearchRequestsTotal .inc ();
685+
686+ Message message = exch .getIn ();
687+
688+ long t0 = System .nanoTime ();
689+ String username = getUsername (exch );
690+
691+ try {
692+ String [] data = fetchSmilesOrMolfile (message );
693+ String queryMol = data [0 ];
694+ String mimeType = data [1 ];
695+
696+ if (queryMol == null || queryMol .isEmpty ()) {
697+ throw new IllegalArgumentException ("Query molecule must be specified" );
698+ }
699+
700+ List <String > smiles ;
701+ try (Session session = graphdb .getSession ()) {
702+ // execute the query
703+ FragmentQuery query = new FragmentQuery (session );
704+
705+ long n0 = System .nanoTime ();
706+ smiles = query .execute (queryMol , mimeType );
707+ long n1 = System .nanoTime ();
708+ fragmentSearchNeo4jSearchDuration .inc ((double ) (n1 - n0 ));
709+ if (smiles == null || smiles .isEmpty ()) {
710+ fragmentSearchMissesTotal .inc (1.0d );
711+ // throw 404
712+ message .setBody ("{\" error\" : \" MoleculeQuery Failed\" ,\" message\" : \" Molecule not found\" }" );
713+ message .setHeader (Exchange .HTTP_RESPONSE_CODE , 404 );
714+ } else {
715+ int size = smiles .size ();
716+ fragmentSearchMoleculesTotal .inc ((double )size );
717+ LOG .info (size + " fragments found" );
718+ message .setBody (smiles );
719+ message .setHeader (Exchange .HTTP_RESPONSE_CODE , 200 );
720+ }
721+ }
722+
723+ } catch (Exception ex ) {
724+ LOG .log (Level .SEVERE , "MoleculeQuery Failed" , ex );
725+ neighbourhoodSearchErrorsTotal .inc ();
726+ message .setBody ("{\" error\" : \" MoleculeQuery Failed\" ,\" message\" :\" " + ex .getLocalizedMessage () + "\" }" );
727+ message .setHeader (Exchange .HTTP_RESPONSE_CODE , 500 );
728+
729+ long t1 = System .nanoTime ();
730+ writeErrorToQueryLog (username , "MoleculeQuery" , t1 - t0 , ex .getLocalizedMessage ());
731+ }
732+ }
733+
633734 void executeNeighbourhoodQuery (Exchange exch ) {
634735
635736 neighbourhoodSearchRequestsTotal .inc ();
0 commit comments