HCE project C++ developers source code library  1.1.1
HCE project developer library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
SphinxFunctionalObject.cpp
Go to the documentation of this file.
1 #include <sstream>
2 #include <unistd.h>
3 #include <Poco/AutoPtr.h>
4 #include <Poco/String.h>
5 
7 #include "SphinxError.hpp"
9 #include "SphinxSchemaFile.hpp"
12 #include "SphinxMessageConst.hpp"
13 
14 namespace HCE
15 {
16 namespace sphinx
17 {
18 //-----------------------------------------------------------------------------
19 SphinxFunctionalObject::SphinxFunctionalObject(const std::string& nodeName_, const std::string& homeDir_, const std::string& indexName_, bool startSearchd_, bool stopSearchd_)
20 :inherited(), SphinxNodeOptions(nodeName_, 0, homeDir_, indexName_), searcher(*this, startSearchd_, stopSearchd_), indexer(*this),
21  loaded(false), checkIncomingDocuments(false), packIncomingDocuments(false), minNumberFieldsPacking(0),
22  logger(), messagesCollection(message_const::messages), message(messagesCollection),
23  matchMode(SPH_MATCH_EXTENDED2), sortMode(SPH_SORT_RELEVANCE), rankingMode(SPH_RANK_DEFAULT), rankExpression("")
24 {
25  if (!homeDir_.empty() && !indexName_.empty())
26  if (loadConfiguration(indexName_))
27  {
29  if (startSearchd_)
30  startSearchd();
31  else
32  {
33  _isError = !easyStart();
34  }
35  }
36 }
37 //-----------------------------------------------------------------------------
38 SphinxFunctionalObject::SphinxFunctionalObject(const std::string& nodeName_, unsigned int nodeNumber_, const std::string& homeDir_, const std::string& indexName_, bool startSearchd_, bool stopSearchd_)
39 :inherited(), SphinxNodeOptions(nodeName_, nodeNumber_, homeDir_, indexName_), searcher(*this, startSearchd_, stopSearchd_), indexer(*this),
40  loaded(false), checkIncomingDocuments(false), packIncomingDocuments(false), minNumberFieldsPacking(0),
41  logger(), messagesCollection(message_const::messages), message(messagesCollection),
42  matchMode(SPH_MATCH_EXTENDED2), sortMode(SPH_SORT_RELEVANCE), rankingMode(SPH_RANK_DEFAULT), rankExpression("")
43 {
44  if (!homeDir_.empty() && !indexName_.empty())
45  if (loadConfiguration(indexName_))
46  {
49  if (startSearchd_)
50  startSearchd();
51  else
52  {
53  _isError = !easyStart();
54  }
55  }
56 }
57 //-----------------------------------------------------------------------------
59 {
60  logger.resetLogStream();
61 }
62 //-----------------------------------------------------------------------------
64 {
65  logger.setLogStream(os);
66 }
67 //-----------------------------------------------------------------------------
68 std::string SphinxFunctionalObject::logMsg(bool isReset)
69 {
70  return logger.logMsg(isReset);
71 }
72 //-----------------------------------------------------------------------------
73 std::ostream& SphinxFunctionalObject::log(void)
74 {
75  return logger.log();
76 }
77 //-----------------------------------------------------------------------------
79 {
80  logger.setLoggable(loggable);
81 }
82 //-----------------------------------------------------------------------------
84 {
85  logger.resetLoggable();
86 }
87 //-----------------------------------------------------------------------------
88 void SphinxFunctionalObject::parseHostPort(const std::string& in, std::string& outHost, unsigned int& outPort) throw (std::exception)
89 {
90  size_t pos = in.find(':');
91  if (pos==std::string::npos)
92  {
94  outPort = std::stoul(Poco::trim(in));
95  }
96  else
97  {
98  outHost = Poco::trim(std::string(in, 0, pos));
99  outPort = std::stoul(Poco::trim(std::string(in, pos+1)));
100  }
101 }
102 //-----------------------------------------------------------------------------
103 void SphinxFunctionalObject::setRankingMode(unsigned int rankingMode_, const std::string& rankExpression_)
104 {
105  rankingMode=rankingMode_;
106  if (!rankExpression_.empty())
107  rankExpression = rankExpression_;
108 }
109 //-----------------------------------------------------------------------------
111 {
112  loaded = false;
113  _isError = false;
114  errorMsg.clear();
116  std::string configFile = getDataDir()+"/"+indexName+"/"+sphinx_search_const::sphinxPropertyFile;
117 
118  try
119  {
120  Poco::AutoPtr<SphinxConfigCreator> pConf = new SphinxConfigCreator(configFile);
121  const std::string listen = pConf->getString(sphinx_search_const::searchdListen);
122  const std::string maxMatches = pConf->getString(sphinx_search_const::searchdMaxMatches);
123 
124  std::string host;
125  unsigned int port = 0;
126 
127  parseHostPort(listen, host, port);
128 
129  setServerHost((host.empty())?sphinx_search_const::defaultHost:host);
131 
132  std::string file = getDataDir()+"/"+indexName+"/"+sphinx_search_const::sphinxSchemaFile;
133  std::ifstream ifs(file.c_str());
134  if (!ifs.is_open())
135  throw Poco::Exception(message(message_const::FILE_NOT_FOUND, file), ERROR_LOAD_CONFIG);
136 
137  std::vector<std::pair<std::string, int> > weights;
138  SphinxSchemaFile schemaFile(ifs);
139  loaded = schemaFile.getFields(weights);
140  ifs.close();
141  if (!loaded)
142  throw Poco::Exception(schemaFile.getErrorMsg(), ERROR_LOAD_CONFIG);
143 
144  ifs.open(file.c_str());
145  if (!ifs.is_open())
146  throw Poco::Exception(message(message_const::FILE_NOT_OPEN, file), ERROR_LOAD_CONFIG);
147 
148  SphinxSchemaFile schema(ifs);
149  std::vector<std::string> schemaNames;
150  loaded = schema.getNames(schemaNames);
151  ifs.close();
152  if (!loaded)
153  throw Poco::Exception(schemaFile.getErrorMsg(), ERROR_LOAD_CONFIG);
154 
155  const unsigned int attributesCount = schema.getAttributesCount();
156  log() << message(message_const::SEARCHD_MAX_MATCHES, maxMatches) << std::endl;
157  log() << message(message_const::SCHEMA_NAMES_SIZE, schemaNames.size()) << std::endl;
158  log() << message(message_const::ATTRIBUTES_COUNT, attributesCount) << std::endl;
159 
160  // realloc memory for manager
162 
163  searcher.setFullSchemaNames(schemaNames);
164  loaded = false;
165  if (searcher.setFieldWeights(weights))
166  {
167  weights.clear();
168 
169  std::vector<std::string> keys;
170  pConf->keys(keys);
171 
172  for (size_t i = 0;i<keys.size();++i)
173  {
174  size_t found = keys[i].find(sphinx_search_const::indexNameField);
175  if (found!=std::string::npos)
176  {
177  found = keys[i].find_first_not_of(' ', found+sphinx_search_const::indexNameField.length());
178  if (found!=std::string::npos)
179  {
180  weights.push_back(std::make_pair(keys[i].substr(found), 1));
181  }
182  }
183  }
184  if (weights.empty())
185  throw Poco::Exception(message(message_const::EMPTY_LIST_OF_INDEX_FILES), ERROR_LOAD_CONFIG);
186 
187  loaded = searcher.setIndexWeights(weights);
188  }
189  }
190  catch(Poco::Exception& e)
191  {
192  applyError(e.message(), e.code());
194  }
195  catch(std::exception& e)
196  {
197  applyError(e.what(), ERROR_LOAD_CONFIG);
199  }
200  return loaded;
201 }
202 //-----------------------------------------------------------------------------
204 {
205  searcher.resizeResultData(matchesCount, attributesCount);
206 }
207 //-----------------------------------------------------------------------------
209 {
210  return searcher.easyStart(matchMode, sortMode, rankingMode, rankExpression);
211 }
212 //-----------------------------------------------------------------------------
214 {
215  return searcher.startSearchd();
216 }
217 //-----------------------------------------------------------------------------
219 {
220  return searcher.stopSearchd();
221 }
222 //-----------------------------------------------------------------------------
224 {
225  return searcher.isActiveSearchd();
226 }
227 //-----------------------------------------------------------------------------
229 {
230  return searcher.isConnected();
231 }
232 //-----------------------------------------------------------------------------
234 {
235  searcher.setMatchMode(matchMode);
236  searcher.setRankingMode(rankingMode, rankExpression);
237  searcher.setSortMode(sortMode);
238  return searcher.open();
239 }
240 //-----------------------------------------------------------------------------
242 {
243  return searcher.close();
244 }
245 //-----------------------------------------------------------------------------
247 {
248  inherited::isError(false);
251  searcher.isError(false);
252  searcher.setErrorMsg("");
253  searcher.setErrorCode(NO_ERROR);
254  indexer.isError(false);
255  indexer.setErrorMsg("");
256  indexer.setErrorCode(NO_ERROR);
257 }
258 //-----------------------------------------------------------------------------
259 void SphinxFunctionalObject::applyError(const std::string& msg, unsigned int code)
260 {
261  _isError = true;
264 }
265 //-----------------------------------------------------------------------------
267 {
268  std::string error;
269  if (inherited::isError())
270  error = inherited::getErrorMsg();
271  else if (searcher.isError())
272  error = searcher.getErrorMsg();
273  else if (indexer.isError())
274  error = indexer.getErrorMsg();
275  return error;
276 }
277 //-----------------------------------------------------------------------------
279 {
280  unsigned int code = NO_ERROR;
281  if (inherited::isError())
282  code = inherited::getErrorCode();
283  else if (searcher.isError())
284  code = searcher.getErrorCode();
285  else if (indexer.isError())
286  code = indexer.getErrorCode();
287  return code;
288 }
289 //-----------------------------------------------------------------------------
290 void SphinxFunctionalObject::setServerHost(const std::string& serverHost_)
291 {
292  searcher.setServerHost(serverHost_);
293 }
294 //-----------------------------------------------------------------------------
296 {
297  return searcher.getServerHost();
298 }
299 //-----------------------------------------------------------------------------
301 {
302  searcher.setServerPort(serverPort_);
303 }
304 //-----------------------------------------------------------------------------
306 {
307  return searcher.getServerPort();
308 }
309 //-----------------------------------------------------------------------------
310 bool SphinxFunctionalObject::setIndexFileName(const std::string& indexFileName_)
311 {
312  return searcher.setIndexFileName(indexFileName_);
313 }
314 //-----------------------------------------------------------------------------
316 {
317  return searcher.getIndexFileName();
318 }
319 //-----------------------------------------------------------------------------
320 unsigned long long SphinxFunctionalObject::getTimeoutedRequests(void) const
321 {
322  return searcher.getTimeoutedRequests();
323 }
324 //-----------------------------------------------------------------------------
326 {
327  searcher.resetTimeoutedRequests();
328 }
329 //-----------------------------------------------------------------------------
330 void SphinxFunctionalObject::setDefaultRequestTimeout(unsigned long defaultRequestTimeout_)
331 {
332  searcher.setDefaultRequestTimeout(defaultRequestTimeout_);
333 }
334 //-----------------------------------------------------------------------------
336 {
337  return searcher.getDefaultRequestTimeout();
338 }
339 //-----------------------------------------------------------------------------
340 std::string SphinxFunctionalObject::Process(const std::string& json)
341 {
342  _isError = false;
343  errorMsg = "";
345  std::string resultData;
346  timeval tvStart, tvStop;
347  gettimeofday(&tvStart, 0); //gettimeofday does not support TZ adjust on Linux.
348  bool needDefaultJson = false;
349  try
350  {
351  SphinxInputJsonMessage inputJsonMessage(json);
352  if (inputJsonMessage.isError())
353  throw Poco::Exception(inputJsonMessage.getErrorMsg(), PARSE_ERROR);
354 
355  if (inputJsonMessage.getType() == SphinxInputJsonMessage::MessageType::mtSearch)
356  {
357  needDefaultJson = true;
358  resultData = searcher.makeSearchCommand(inputJsonMessage.getData());
359  if (resultData.empty())
360  resultData = makeDefaultJSON(message(message_const::EMPTY_RESULT_DATA));
361  }
362  else if (inputJsonMessage.getType() == SphinxInputJsonMessage::MessageType::mtIndex)
363  {
364  indexer.makeIndexCommand(inputJsonMessage.getData());
365  }
366  else if (inputJsonMessage.getType() == SphinxInputJsonMessage::MessageType::mtManage)
367  {
368  indexer.makeAdminCommand(inputJsonMessage.getData(), resultData);
369  }
370  else
371  throw Poco::Exception(message(message_const::INCORRECT_JSON_TYPE), COMMAND_ERROR);
372 
373  }
374  catch(Poco::Exception& e)
375  {
376  applyError(e.message(), e.code());
377  if (needDefaultJson)
378  resultData = makeDefaultJSON(message(message_const::ERROR, getErrorMsg()));
379  }
380  catch(std::exception& e)
381  {
382  applyError(e.what(), COMMAND_ERROR);
383  if (needDefaultJson)
384  resultData = makeDefaultJSON(message(message_const::ERROR, getErrorMsg()));
385  }
386 
387  std::string resJson;
388  gettimeofday(&tvStop, 0);
389 
390  SphinxOutputJsonMessage outputMessage;
391  outputMessage.setErrorCode(getErrorCode());
392  outputMessage.setErrorMessage(getErrorMsg());
393  outputMessage.setData(resultData);
394  outputMessage.setTime(SphinxSearcher::getTimeInterval(tvStart, tvStop)/1000);
395  outputMessage.serialize(resJson);
396 
397  if (outputMessage.isError())
399  << message(message_const::ERROR_MSG, outputMessage.getErrorMsg())
400  << message(message_const::ERROR_CODE, outputMessage.getErrorCode()) << std::endl;
401 
402  return resJson;
403 }
404 //-----------------------------------------------------------------------------
406 {
407  _isError = false;
408  errorMsg.clear();
410  std::string resultData;
411  timeval tvStart, tvStop;
412  gettimeofday(&tvStart, 0); //gettimeofday does not support TZ adjust on Linux.
413  bool needDefaultJson = false;
414  try
415  {
416  if (inputJsonMessage.getType() == SphinxInputJsonMessage::MessageType::mtSearch)
417  {
418  needDefaultJson = true;
419  resultData = searcher.makeSearchCommand(inputJsonMessage.getData());
420  if (resultData.empty())
421  resultData = makeDefaultJSON(message(message_const::EMPTY_RESULT_DATA));
422  }
423  else if (inputJsonMessage.getType() == SphinxInputJsonMessage::MessageType::mtIndex)
424  {
425  indexer.makeIndexCommand(inputJsonMessage.getData());
426  }
427  else if (inputJsonMessage.getType() == SphinxInputJsonMessage::MessageType::mtManage)
428  {
429  indexer.makeAdminCommand(inputJsonMessage.getData(), resultData);
430  }
431  else
432  throw Poco::Exception(message(message_const::INCORRECT_JSON_TYPE), COMMAND_ERROR);
433  }
434  catch(Poco::Exception& e)
435  {
436  applyError(e.message(), e.code());
437  if (needDefaultJson)
438  resultData = makeDefaultJSON(message(message_const::ERROR, getErrorMsg()));
439  }
440  catch(std::exception& e)
441  {
442  applyError(e.what(), COMMAND_ERROR);
443  if (needDefaultJson)
444  resultData = makeDefaultJSON(message(message_const::ERROR, getErrorMsg()));
445  }
446 
447  gettimeofday(&tvStop, 0);
448 
449  SphinxOutputJsonMessage outputMessage;
450  outputMessage.setErrorCode(getErrorCode());
451  outputMessage.setErrorMessage(getErrorMsg());
452  outputMessage.setData(resultData);
453  outputMessage.setTime(SphinxSearcher::getTimeInterval(tvStart, tvStop)/1000);
454 
455  return outputMessage;
456 }
457 //-----------------------------------------------------------------------------
458 std::string SphinxFunctionalObject::makeDefaultJSON(const std::string& logMsg)
459 {
460  log() << logMsg << " " << message(message_const::GENERATE_DEFAULT_JSON) << std::endl;
461  SphinxDefaultJSON defaultJson;
462  return defaultJson.getJSON();
463 }
464 //-----------------------------------------------------------------------------
465 //-----------------------------------------------------------------------------
466 } // namespace sphinx
467 } // namespace HCE