|
|
@@ -1,76 +1,22 @@
|
|
|
<?php
|
|
|
|
|
|
-require dirname(__FILE__) . '/vendor/autoload.php';
|
|
|
-require dirname(__FILE__) . '/config.php';
|
|
|
-
|
|
|
+require_once dirname(__FILE__) . '/vendor/autoload.php';
|
|
|
+require_once dirname(__FILE__) . '/config.php';
|
|
|
+require_once dirname(__FILE__) . '/logger.php';
|
|
|
+require_once dirname(__FILE__) . '/pdo.php';
|
|
|
|
|
|
+use Monolog\Logger;
|
|
|
+use Monolog\Handler\StreamHandler;
|
|
|
|
|
|
class Greeter extends \Mint\Tulip\V1\SearchStub
|
|
|
{
|
|
|
- private $_pdo = null;
|
|
|
- private function log($level,$message){
|
|
|
- $output = "[\033[32m".date("Y/m/d h:i:sa") ."\033[0m] ";
|
|
|
- if($level === 'error'){
|
|
|
- $output .= "\033[41m" . $level . "\033[0m ";
|
|
|
- }else{
|
|
|
- $output .= $level;
|
|
|
- }
|
|
|
-
|
|
|
- $output .= ' ' . $message.PHP_EOL;
|
|
|
- if($level === 'error'){
|
|
|
- fwrite(STDERR,$output);
|
|
|
- }else{
|
|
|
- fwrite(STDOUT,$output);
|
|
|
- }
|
|
|
- }
|
|
|
- private function connectDb(){
|
|
|
- /**
|
|
|
- * 连接数据库
|
|
|
- */
|
|
|
- $db = Config['database']['driver'];
|
|
|
- $db .= ":host=".Config['database']['host'];
|
|
|
- $db .= ";port=".Config['database']['port'];
|
|
|
- $db .= ";dbname=".Config['database']['name'];
|
|
|
- $db .= ";user=".Config['database']['user'];
|
|
|
- $db .= ";password=".Config['database']['password'].";";
|
|
|
- echo 'connect to db host='.Config['database']['host'] . ' name='.Config['database']['name'].PHP_EOL;
|
|
|
- try {
|
|
|
- $PDO = new PDO($db,
|
|
|
- Config['database']['user'],
|
|
|
- Config['database']['password'],
|
|
|
- array(PDO::ATTR_PERSISTENT=>true));
|
|
|
- }catch(PDOException $e) {
|
|
|
- echo 'connect to db fail'.PHP_EOL;
|
|
|
- print $e->getMessage();
|
|
|
- return false;
|
|
|
- }
|
|
|
- $PDO->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
|
|
- $this->_pdo = $PDO;
|
|
|
- }
|
|
|
- private function dbSelect($query, $params=null)
|
|
|
- {
|
|
|
- if($this->_pdo === null){
|
|
|
- return false;
|
|
|
- }
|
|
|
- if (isset($params)) {
|
|
|
- $stmt = $this->_pdo->prepare($query);
|
|
|
- $stmt->execute($params);
|
|
|
- } else {
|
|
|
- $stmt = $this->_pdo->query($query);
|
|
|
- }
|
|
|
- return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Create a new instance.
|
|
|
- *
|
|
|
- * @return void
|
|
|
- */
|
|
|
+ private $log = null;
|
|
|
public function __construct()
|
|
|
{
|
|
|
- $this->connectDb();
|
|
|
+ // create a log channel
|
|
|
+ $this->log = new Logger('tulip');
|
|
|
+ $this->log->pushHandler(new StreamHandler(__DIR__ . '/logs/tulip-' . date("Y-m-d") . '.log'));
|
|
|
}
|
|
|
-
|
|
|
public function Pali(
|
|
|
\Mint\Tulip\V1\SearchRequest $request,
|
|
|
\Grpc\ServerContext $context
|
|
|
@@ -79,30 +25,32 @@ class Greeter extends \Mint\Tulip\V1\SearchStub
|
|
|
foreach ($request->getKeywords()->getIterator() as $word) {
|
|
|
$keyWords[] = $word;
|
|
|
}
|
|
|
- echo "[".date("Y/m/d h:i:sa") ."] pali search: request words = ".implode(',',$keyWords) .PHP_EOL;
|
|
|
+ $msg = "[" . date("Y/m/d h:i:sa") . "] pali search: request words = " . implode(',', $keyWords);
|
|
|
+ echo $msg . PHP_EOL;
|
|
|
+ $this->log->info($msg);
|
|
|
|
|
|
+ $pdo = new PdoHelper;
|
|
|
+ $pdo->connectDb();
|
|
|
/**
|
|
|
* 查询业务逻辑
|
|
|
*/
|
|
|
|
|
|
- $searchChapters = [];
|
|
|
- $searchBooks = [];
|
|
|
- $searchBookId = [];
|
|
|
$bookId = [];
|
|
|
- if($request->getBooks()->count()>0){
|
|
|
+ if ($request->getBooks()->count() > 0) {
|
|
|
foreach ($request->getBooks()->getIterator() as $book) {
|
|
|
$bookId[] = $book;
|
|
|
}
|
|
|
- $queryBookId = ' AND pcd_book_id in ('.implode(',',$bookId).') ';
|
|
|
- }else{
|
|
|
+ $queryBookId = ' AND pcd_book_id in (' . implode(',', $bookId) . ') ';
|
|
|
+ } else {
|
|
|
$queryBookId = '';
|
|
|
}
|
|
|
- echo 'query books = '.implode(',',$bookId).PHP_EOL;
|
|
|
+ $msg = 'query books = ' . implode(',', $bookId);
|
|
|
+ echo $msg . PHP_EOL;
|
|
|
+ $this->log->info($msg);
|
|
|
|
|
|
$matchMode = $request->getMatchMode();
|
|
|
- echo 'query mode = '.$matchMode.PHP_EOL;
|
|
|
+ echo 'query mode = ' . $matchMode . PHP_EOL;
|
|
|
$param = [];
|
|
|
- $countParam = [];
|
|
|
switch ($matchMode) {
|
|
|
case 'complete':
|
|
|
case 'case':
|
|
|
@@ -110,18 +58,23 @@ class Greeter extends \Mint\Tulip\V1\SearchStub
|
|
|
$querySelect_rank_base = " ts_rank('{0.1, 1, 0.3, 0.2}',
|
|
|
full_text_search_weighted,
|
|
|
websearch_to_tsquery('pali', ?)) ";
|
|
|
- $querySelect_rank_head = implode('+',
|
|
|
- array_fill(0, count($keyWords),
|
|
|
- $querySelect_rank_base));
|
|
|
+ $querySelect_rank_head = implode(
|
|
|
+ '+',
|
|
|
+ array_fill(
|
|
|
+ 0,
|
|
|
+ count($keyWords),
|
|
|
+ $querySelect_rank_base
|
|
|
+ )
|
|
|
+ );
|
|
|
|
|
|
- $param = array_merge($param,$keyWords);
|
|
|
+ $param = array_merge($param, $keyWords);
|
|
|
$querySelect_rank = " {$querySelect_rank_head} AS rank, ";
|
|
|
$querySelect_highlight = " ts_headline('pali', content,
|
|
|
websearch_to_tsquery('pali', ?),
|
|
|
'StartSel = ~~, StopSel = ~~,MaxWords=3500,
|
|
|
MinWords=3500,HighlightAll=TRUE')
|
|
|
AS highlight,";
|
|
|
- array_push($param,implode(' ',$keyWords));
|
|
|
+ array_push($param, implode(' ', $keyWords));
|
|
|
break;
|
|
|
case 'similar':
|
|
|
# 形似,去掉变音符号
|
|
|
@@ -131,7 +84,7 @@ class Greeter extends \Mint\Tulip\V1\SearchStub
|
|
|
full_text_search_weighted_unaccent,
|
|
|
websearch_to_tsquery('pali_unaccent', ?))
|
|
|
AS rank, ";
|
|
|
- $param[] = $key;
|
|
|
+ $param[] = $key;
|
|
|
$querySelect_highlight = " ts_headline('pali_unaccent', content,
|
|
|
websearch_to_tsquery('pali_unaccent', ?),
|
|
|
'StartSel = ~~, StopSel = ~~,
|
|
|
@@ -141,20 +94,30 @@ class Greeter extends \Mint\Tulip\V1\SearchStub
|
|
|
$param[] = $key;
|
|
|
break;
|
|
|
}
|
|
|
- $_queryWhere = $this->makeQueryWhere($keyWords,$matchMode);
|
|
|
+ $_queryWhere = $this->makeQueryWhere($keyWords, $matchMode);
|
|
|
$queryWhere = $_queryWhere['query'];
|
|
|
- $param = array_merge($param,$_queryWhere['param']);
|
|
|
+ $param = array_merge($param, $_queryWhere['param']);
|
|
|
|
|
|
$querySelect_2 = " book,paragraph,content ";
|
|
|
|
|
|
$queryCount = "SELECT count(*) as co FROM fts_texts WHERE {$queryWhere} {$queryBookId};";
|
|
|
- $resultCount = $this->dbSelect($queryCount, $_queryWhere['param']);
|
|
|
- $total = $resultCount[0]['co'];
|
|
|
+ $resultCount = $pdo->dbSelect($queryCount, $_queryWhere['param']);
|
|
|
+ if (
|
|
|
+ is_array($resultCount) &&
|
|
|
+ count($resultCount) > 0 &&
|
|
|
+ isset($resultCount[0]['co'])
|
|
|
+ ) {
|
|
|
+ $total = $resultCount[0]['co'];
|
|
|
+ } else {
|
|
|
+ logger('warning', 'result must be of type array' . $pdo->errorInfo());
|
|
|
+ $this->log->error('result must be of type array' . $pdo->errorInfo());
|
|
|
+ $total = 0;
|
|
|
+ }
|
|
|
|
|
|
- if($request->hasPage()){
|
|
|
+ if ($request->hasPage()) {
|
|
|
$limit = $request->getPage()->getSize();
|
|
|
$offset = $request->getPage()->getIndex();
|
|
|
- }else{
|
|
|
+ } else {
|
|
|
$limit = 10;
|
|
|
$offset = 0;
|
|
|
}
|
|
|
@@ -183,21 +146,25 @@ class Greeter extends \Mint\Tulip\V1\SearchStub
|
|
|
$param[] = $limit;
|
|
|
$param[] = $offset;
|
|
|
|
|
|
- $result = $this->dbSelect($query, $param);
|
|
|
-
|
|
|
- //返回数据
|
|
|
+ $result = $pdo->dbSelect($query, $param);
|
|
|
+ //返回数据
|
|
|
$response = new \Mint\Tulip\V1\SearchResponse();
|
|
|
$output = $response->getItems();
|
|
|
- foreach ($result as $row) {
|
|
|
- $item = new \Mint\Tulip\V1\SearchResponse\Item;
|
|
|
- $item->setRank($row['rank']);
|
|
|
- $item->setHighlight($row['highlight']);
|
|
|
- $item->setBook($row['book']);
|
|
|
- $item->setParagraph($row['paragraph']);
|
|
|
- $item->setContent($row['content']);
|
|
|
- $output[] = $item;
|
|
|
+
|
|
|
+ if ($result) {
|
|
|
+ foreach ($result as $row) {
|
|
|
+ $item = new \Mint\Tulip\V1\SearchResponse\Item;
|
|
|
+ $item->setRank($row['rank']);
|
|
|
+ $item->setHighlight($row['highlight']);
|
|
|
+ $item->setBook($row['book']);
|
|
|
+ $item->setParagraph($row['paragraph']);
|
|
|
+ $item->setContent($row['content']);
|
|
|
+ $output[] = $item;
|
|
|
+ }
|
|
|
}
|
|
|
- echo "total={$total}".PHP_EOL;
|
|
|
+
|
|
|
+ echo "total={$total}" . PHP_EOL;
|
|
|
+ $this->log->info("total={$total}");
|
|
|
$response->setTotal($total);
|
|
|
return $response;
|
|
|
}
|
|
|
@@ -216,155 +183,48 @@ class Greeter extends \Mint\Tulip\V1\SearchStub
|
|
|
foreach ($request->getKeywords()->getIterator() as $word) {
|
|
|
$keyWords[] = $word;
|
|
|
}
|
|
|
- echo "book list: request words = ".implode(',',$keyWords) .PHP_EOL;
|
|
|
+ echo "book list: request words = " . implode(',', $keyWords) . PHP_EOL;
|
|
|
/**
|
|
|
* 查询业务逻辑
|
|
|
*/
|
|
|
+ $pdo = new PdoHelper;
|
|
|
+ $pdo->connectDb();
|
|
|
|
|
|
- $searchChapters = [];
|
|
|
- $searchBooks = [];
|
|
|
- $searchBookId = [];
|
|
|
- $bookId = [];
|
|
|
- if($request->getBooks()->count()>0){
|
|
|
- foreach ($request->getBooks()->getIterator() as $book) {
|
|
|
- $bookId[] = $book;
|
|
|
- }
|
|
|
- $queryBookId = ' AND pcd_book_id in ('.implode(',',$bookId).') ';
|
|
|
- }else{
|
|
|
- $queryBookId = '';
|
|
|
- }
|
|
|
- echo 'query books = '.implode(',',$bookId).PHP_EOL;
|
|
|
-
|
|
|
- $matchMode = $request->getMatchMode();
|
|
|
- echo 'query mode = '.$matchMode.PHP_EOL;
|
|
|
- $queryWhere = $this->makeQueryWhere($keyWords,$matchMode);
|
|
|
- $query = "SELECT pcd_book_id, count(*) as co FROM fts_texts WHERE {$queryWhere['query']} {$queryBookId} GROUP BY pcd_book_id ORDER BY co DESC;";
|
|
|
- $result = $this->dbSelect($query, $queryWhere['param']);
|
|
|
- //返回数据
|
|
|
- $response = new \Mint\Tulip\V1\BookListResponse();
|
|
|
- $output = $response->getItems();
|
|
|
- foreach ($result as $row) {
|
|
|
- $item = new \Mint\Tulip\V1\BookListResponse\Item;
|
|
|
- $item->setBook($row['pcd_book_id']);
|
|
|
- $item->setCount($row['co']);
|
|
|
- $output[] = $item;
|
|
|
- }
|
|
|
- echo "total=".count($output).PHP_EOL;
|
|
|
- return $response;
|
|
|
- }
|
|
|
- /**
|
|
|
- * @param \Mint\Tulip\V1\UploadDictionaryRequest $request client request
|
|
|
- * @param \Grpc\ServerContext $context server request context
|
|
|
- * @return \Mint\Tulip\V1\UploadDictionaryResponse for response data, null if if error occured
|
|
|
- * initial metadata (if any) and status (if not ok) should be set to $context
|
|
|
- */
|
|
|
- public function UploadDictionary(
|
|
|
- \Mint\Tulip\V1\UploadDictionaryRequest $request,
|
|
|
- \Grpc\ServerContext $context
|
|
|
- ): ?\Mint\Tulip\V1\UploadDictionaryResponse {
|
|
|
- $response = new \Mint\Tulip\V1\UploadDictionaryResponse();
|
|
|
- $data = $request->getData();
|
|
|
- $this->log('debug',"received data size=".strlen($data));
|
|
|
- $dir = dirname(__FILE__) . '/storage';
|
|
|
- if(!is_dir($dir)){
|
|
|
- $res = mkdir($dir,0700,true);
|
|
|
- if(!$res){
|
|
|
- $this->log('error',"mkdir fail path=".$dir);
|
|
|
- $response->setError(1);
|
|
|
- return $response;
|
|
|
+ $bookId = [];
|
|
|
+ if ($request->getBooks()->count() > 0) {
|
|
|
+ foreach ($request->getBooks()->getIterator() as $book) {
|
|
|
+ $bookId[] = $book;
|
|
|
}
|
|
|
+ $queryBookId = ' AND pcd_book_id in (' . implode(',', $bookId) . ') ';
|
|
|
+ } else {
|
|
|
+ $queryBookId = '';
|
|
|
}
|
|
|
- $filename = $dir.'/pali-'.date("Y-m-d-h-i-sa").'.syn';
|
|
|
- $size = file_put_contents($filename,$data);
|
|
|
-
|
|
|
- if($size === false){
|
|
|
- $this->log('error',"file write fail ");
|
|
|
- $response->setError(1);
|
|
|
- return $response;
|
|
|
- }
|
|
|
- $this->log('debug',"save file size={$size} ");
|
|
|
- $response->setError(0);
|
|
|
- return $response;
|
|
|
- }
|
|
|
+ echo 'query books = ' . implode(',', $bookId) . PHP_EOL;
|
|
|
|
|
|
- public function Update(
|
|
|
- \Mint\Tulip\V1\UpdateRequest $request,
|
|
|
- \Grpc\ServerContext $context
|
|
|
- ): ?\Mint\Tulip\V1\UpdateResponse {
|
|
|
- $response = new \Mint\Tulip\V1\UpdateResponse();
|
|
|
- $book = $request->getBook();
|
|
|
- $paragraph = $request->getParagraph();
|
|
|
- $this->log('debug',"update start book={$book} para={$paragraph} ");
|
|
|
- $now = date("Y-m-d H:i:s");
|
|
|
- //查询是否存在
|
|
|
- $query = 'SELECT id from fts_texts where book=? and paragraph = ?';
|
|
|
- $result = $this->dbSelect($query, [$book,$paragraph]);
|
|
|
- if(count($result) >0 ){
|
|
|
- //存在 update
|
|
|
- $query = 'UPDATE fts_texts set
|
|
|
- "bold_single"=?,
|
|
|
- "bold_double"=?,
|
|
|
- "bold_multiple"=?,
|
|
|
- "content"=?,
|
|
|
- "pcd_book_id"=?,
|
|
|
- "updated_at"=? where id=? ';
|
|
|
- $update = $this->dbSelect($query, [
|
|
|
- $request->getBold1(),
|
|
|
- $request->getBold2(),
|
|
|
- $request->getBold3(),
|
|
|
- $request->getContent(),
|
|
|
- $request->getPcdBookId(),
|
|
|
- $now,
|
|
|
- $result[0]['id']
|
|
|
- ]);
|
|
|
- }else{
|
|
|
- // new
|
|
|
- $query = "INSERT INTO fts_texts (
|
|
|
- book,
|
|
|
- paragraph,
|
|
|
- bold_single,
|
|
|
- bold_double,
|
|
|
- bold_multiple,
|
|
|
- \"content\",
|
|
|
- created_at,
|
|
|
- updated_at,
|
|
|
- pcd_book_id) VALUES
|
|
|
- (?,?,?,?,?,?,?,?,? )";
|
|
|
- $insert = $this->dbSelect($query, [
|
|
|
- $request->getBook(),
|
|
|
- $request->getParagraph(),
|
|
|
- $request->getBold1(),
|
|
|
- $request->getBold2(),
|
|
|
- $request->getBold3(),
|
|
|
- $request->getContent(),
|
|
|
- $now,
|
|
|
- $now,
|
|
|
- $request->getPcdBookId(),
|
|
|
- ]);
|
|
|
+ $matchMode = $request->getMatchMode();
|
|
|
+ echo 'query mode = ' . $matchMode . PHP_EOL;
|
|
|
+ $queryWhere = $this->makeQueryWhere($keyWords, $matchMode);
|
|
|
+ $query = "SELECT pcd_book_id, count(*) as co FROM fts_texts WHERE {$queryWhere['query']} {$queryBookId} GROUP BY pcd_book_id ORDER BY co DESC;";
|
|
|
+ $result = $pdo->dbSelect($query, $queryWhere['param']);
|
|
|
+ //返回数据
|
|
|
+ $response = new \Mint\Tulip\V1\BookListResponse();
|
|
|
+ $output = $response->getItems();
|
|
|
+ if ($result) {
|
|
|
+ foreach ($result as $row) {
|
|
|
+ $item = new \Mint\Tulip\V1\BookListResponse\Item;
|
|
|
+ $item->setBook($row['pcd_book_id']);
|
|
|
+ $item->setCount($row['co']);
|
|
|
+ $output[] = $item;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- $response->setCount(0);
|
|
|
+ echo "total=" . count($output) . PHP_EOL;
|
|
|
return $response;
|
|
|
}
|
|
|
|
|
|
- private function _updateIndex($book,$para){
|
|
|
- $query = 'UPDATE fts_texts SET content = content,
|
|
|
- bold_single = bold_single,
|
|
|
- bold_double = bold_double,
|
|
|
- bold_multiple = bold_multiple
|
|
|
- WHERE book = ? AND paragraph = ?';
|
|
|
- $update = $this->dbSelect($query, [$book,$para]);
|
|
|
- }
|
|
|
-
|
|
|
- private function _updateIndexAll(){
|
|
|
- $query = 'UPDATE fts_texts SET content = content,
|
|
|
- bold_single = bold_single,
|
|
|
- bold_double = bold_double,
|
|
|
- bold_multiple = bold_multiple';
|
|
|
- $update = $this->dbSelect($query);
|
|
|
- }
|
|
|
|
|
|
- private function makeQueryWhere($key,$match){
|
|
|
+ private function makeQueryWhere($key, $match)
|
|
|
+ {
|
|
|
$param = [];
|
|
|
$queryWhere = '';
|
|
|
switch ($match) {
|
|
|
@@ -372,10 +232,13 @@ class Greeter extends \Mint\Tulip\V1\SearchStub
|
|
|
case 'case':
|
|
|
# code...
|
|
|
$queryWhereBase = " full_text_search_weighted @@ websearch_to_tsquery('pali', ?) ";
|
|
|
- $queryWhereBody = implode(' or ', array_fill(0, count($key),
|
|
|
- $queryWhereBase));
|
|
|
+ $queryWhereBody = implode(' or ', array_fill(
|
|
|
+ 0,
|
|
|
+ count($key),
|
|
|
+ $queryWhereBase
|
|
|
+ ));
|
|
|
$queryWhere = " ({$queryWhereBody}) ";
|
|
|
- $param = array_merge($param,$key);
|
|
|
+ $param = array_merge($param, $key);
|
|
|
break;
|
|
|
case 'similar':
|
|
|
# 形似,去掉变音符号
|
|
|
@@ -384,13 +247,16 @@ class Greeter extends \Mint\Tulip\V1\SearchStub
|
|
|
$param = [$key];
|
|
|
break;
|
|
|
};
|
|
|
- return (['query'=>$queryWhere,'param'=>$param]);
|
|
|
+ return (['query' => $queryWhere, 'param' => $param]);
|
|
|
}
|
|
|
|
|
|
private function getWordEn($strIn)
|
|
|
{
|
|
|
- $out = str_replace(["ā","ī","ū","ṅ","ñ","ṭ","ḍ","ṇ","ḷ","ṃ"],
|
|
|
- ["a","i","u","n","n","t","d","n","l","m"], $strIn);
|
|
|
+ $out = str_replace(
|
|
|
+ ["ā", "ī", "ū", "ṅ", "ñ", "ṭ", "ḍ", "ṇ", "ḷ", "ṃ"],
|
|
|
+ ["a", "i", "u", "n", "n", "t", "d", "n", "l", "m"],
|
|
|
+ $strIn
|
|
|
+ );
|
|
|
return ($out);
|
|
|
}
|
|
|
}
|