您的位置:首页 > 数据库 > Mongodb

php + MongoDB + Sphinx 实现全文检索 (二)

2016-12-27 21:12 751 查看
上一篇文章写了大体思路, IndexDriver 只给了个接口, mysql 数据转移, sphinx 索引配置文件的建立, 这些地方都没有给出.

本着 talk is cheap 的原则,将这部分代码在这里补全.


IndexDriver

这里仅列出一个示例性质的具体实现类.

首先给出一个由其派生的对接mongo的抽象类,所有由mongo数据建立的索引都继承该类:

<?php
abstract class MongoIndexDriver implements IndexDriver {

private $mongo_host;
private $index_name;
private $mongo_conn;

public function __construct($mongo_host) {
$this->mongo_host = $mongo_host;
}

/**
* {@inheritDoc}
* @see IndexDriver::getIndexName()
*/
public function getIndexName() {
// use driver file name as index name. in this way, the index name
// is always unique.
if (!$this->index_name) {
$class_name = get_class($this);
$this->index_name = chop($class_name, "Driver");
}
return $this->index_name;
}

protected function setMongoHost($host) {
$this->mongo_host = $host;
}

protected function table($table_name, $database_name = "kaiba") {
if (!$this->mongo_conn) {
$this->mongo_conn = new MongoClient($this->mongo_host);
}
return $this->mongo_conn->$database_name->$table_name;
}
}

然后是一个具体的实现类:

<?php
require_once SCRIPT_PATH.'/base/IndexDriver.php';
require_once SCRIPT_PATH.'/base/MongoIndexDriver.php';
require_once SCRIPT_PATH.'/base/IndexField.php';

class ExampleDriver extends MongoIndexDriver {

const REFRESH_INTERVAL = 7 * 24 * 60;

private $fields;
private $mongo_table;

public function __construct() {
$ini = parse_ini_file(CONFIG_PATH, true);
parent::__construct($ini['mongo']['host'].":".$ini['mongo']['port']);

$this->fields = array(
IndexField::createIntField("_id1"),
IndexField::createIntField("_id2"),
IndexField::createIntField("_id3"),
IndexField::createIntField("_id4"),
IndexField::createIntField("code"),
IndexField::createIntField("type"),
IndexField::createField("name"),
IndexField::createField("content"),
IndexField::createField("message"),
);
}

/**
* {@inheritDoc}
* @see IndexDriver::getIndexFields()
*/
public function getIndexFields() {
return $this->fields;
}

/**
* {@inheritDoc}
* @see IndexDriver::getValues()
*/
public function getValues($offset, $limit) {
$mongo_cursor = $this->table("example_table")
->find(array(), array(
"_id",
"code",
"type",
"name",
"content",
"message",
))
->skip($offset)
->limit($limit);
$result_count = $mongo_cursor->count();
if ($result_count <= 0) {
return null;
}

$result = array();
foreach ($mongo_cursor as $k => $v) {
$value = array();
$_id1 = $_id2 = $_id3 = $_id4 = "";

// mongoId -> int
$id_string = $v['_id']."";
for ($j = 0; $j < 4; $j ++) {
$id_sub = substr($id_string, $j * 6, 6);
$segment = hexdec($id_sub);
${"_id".($j + 1)} = $segment;
}

$value['_id1'] = $_id1;
$value['_id2'] = $_id2;
$value['_id3'] = $_id3;
$value['_id4'] = $_id4;
$value['code'] = $v['code'];
$value['type'] = $v['type'];
$value['name'] = $v['name'];
$value['content'] = $v['content'];
$value['message'] = $v['message'];

$result[] = $value;
}

return $result;
}

/**
* {@inheritDoc}
* @see IndexDriver::shouldRefreshIndex()
*/
public function shouldRefreshIndex($last_refresh_time) {
$hour = (int) date('H');
// only refresh index in midnight
if ($hour > 4) {
return false;
}
$minutes = (time() - $last_refresh_time) / 60;
return $minutes + 5 > self::REFRESH_INTERVAL;
}

/**
* {@inheritDoc}
* @see IndexDriver::generateDocument()
*/
public function generateDocument() {
// TODO Auto-generated method stub
}

}


索引建立工具类:

<?php
require_once SCRIPT_PATH.'/base/IndexDriver.php';
require_once SCRIPT_PATH.'/base/IndexField.php';
require_once SCRIPT_PATH.'/utils/Logger.php';

/**
* @author lx
* date: 2016-11-25
* generate sphinx conf. used by searchd and indexer.
*/
class SphinxConfCreator {

private $mysql_host;
private $mysql_port;
private $mysql_user;
private $mysql_password;
private $mysql_database;

private $conf_file;
private $index_data_path;
private $charset_dictpath;
private $pid_file;
private $log_file;
private $query_log_file;

private $drivers;
private $logger;

public function __construct(array $drivers) {
$this->logger = new Logger("SphinxConfGenerator");
if (empty($drivers)) {
$msg = "IndexDriver array empty";
$this->logger->e($msg);
throw new Exception($msg);
}
foreach ($drivers as $name => $driver) {
if (! $driver instanceof IndexDriver) {
$msg = "need a valid IndexDriver";
$this->logger->e($msg);
throw new Exception($msg);
}
}
$this->drivers = $drivers;
}

public function setMysqlHost($host, $port = null) {
$this->mysql_host = $host;
$this->mysql_port = $port;
return $this;
}

public function setMysqlUser($user, $password) {
$this->mysql_user = $user;
$this->mysql_password = $password;
return $this;
}

public function setMysqlDatabase($database) {
$this->mysql_database = $database;
return $this;
}

public function setConfFilePath($path) {
$this->conf_file = $path;
return $this;
}

public function setConfIndexDataPath($path) {
$this->index_data_path = $path;
return $this;
}

public function setConfCharsetDictPath($path) {
$this->charset_dictpath = $path;
return $this;
}

public function setConfPidFilePath($path) {
$this->pid_file = $path;
return $this;
}

public function setConfLogFilePath($path) {
$this->log_file = $path;
return $this;
}

public function setConfQueryLogFilePath($path) {
$this->query_log_file = $path;
return $this;
}

public function create() {
$this->checkPath($this->conf_file, "conf file");
$this->checkPath($this->charset_dictpath, "charset dict path", true);
$this->checkPath($this->index_data_path, "index data path");
$this->checkPath($this->pid_file, "pid file");
$this->checkPath($this->log_file, "log file");
$this->checkPath($this->query_log_file, "query log file");

$content = "";
foreach ($this->drivers as $name => $driver) {
$content .= $this->sourceConf($driver);
$content .= $this->indexConf($driver);
}
$content .= $this->indexerConf();
$content .= $this->searchdConf();
file_put_contents($this->conf_file, $content);

// in case below files does not exist...
touch($this->pid_file);
touch($this->log_file);
touch($this->query_log_file);
}

// ==========================================================

public function sourceConf($driver) {
$attr_lines = "";
$fields = $driver->getIndexFields();
foreach ($fields as $field) {
if (!$field->isSphinxField()) {
$attr_lines .= $this->getSourceAttrLine($field);
}
}

$str = <<<EOF

source {$driver->getIndexName()}_src
{
type                    = mysql

sql_host                = {$this->mysql_host}
sql_user                = {$this->mysql_user}
sql_pass                = {$this->mysql_password}
sql_db                  = {$this->mysql_database}
sql_port                = {$this->mysql_port}
sql_query_pre           = SET NAMES utf8

sql_query_range         = SELECT MIN(id), MAX(id) FROM {$driver->getIndexName()}
sql_range_step          = 1000
sql_query               = {$this->getSourceSqlQuery($driver)}

{$attr_lines}
}

EOF;

return $str;
}

// ==========================================================

public function indexConf($driver) {
$str = <<<EOF

index {$driver->getIndexName()}
{
source             = {$driver->getIndexName()}_src
path               = {$this->index_data_path}/{$driver->getIndexName()}
docinfo            = extern
mlock              = 0
morphology         = none
min_word_len       = 1
html_strip         = 0

charset_dictpath   = {$this->charset_dictpath}
charset_type       = zh_cn.utf-8
}

EOF;
return $str;
}

// ==========================================================

public function indexerConf() {
$str = <<<EOF

indexer
{
mem_limit          = 128M
}

EOF;
return $str;
}

// ==========================================================

public function searchdConf() {
$str = <<<EOF

searchd
{
listen             = 9312
read_timeout       = 5
max_children       = 30
max_matches        = 1000
seamless_rotate    = 1
preopen_indexes    = 1
unlink_old         = 1
pid_file           = {$this->pid_file}
log                = {$this->log_file}
query_log          = {$this->query_log_file}
}

EOF;
return $str;
}

// ==========================================================

private function checkPath($path, $where = "", $check_readable = false) {
$msg = "";
if ($check_readable) {
if (!is_readable($path)) {
$msg = "file not exists: $path";
}
} else if (empty($path)) {
$msg = "path empty";
} else {
// check parent dir
$dir = dirname($path);
if (!file_exists($dir)) {
mkdir($dir);
}
if (!is_dir($dir)) {
$msg = "parent dir not exists: $dir";
} else if (!is_readable($dir)) {
$msg = "parent dir not readable: $dir";
}
}

if (!empty($msg)) {
$msg = "$where, $msg";
$this->logger->e($msg);
throw new Exception($msg);
}
}

private function getSourceAttrLine($field) {
$line = sprintf("    %s = %s \n", $field->getSphinxType(), $field->getName());
return $line;
}

private function getSourceSqlQuery($driver) {
$sql_query = "SELECT id,";
$fields = $driver->getIndexFields();
$table = $driver->getIndexName();
$field_count = count($fields);
for ($i = 0; $i < $field_count; $i ++) {
$field_name = $fields[$i]->getName();
$sql_query = "$sql_query $field_name";
if ($i + 1 < $field_count) {
$sql_query = "$sql_query,";
}
}
$sql_query = "$sql_query FROM $table WHERE id>=\$start AND id<=\$end";
return $sql_query;
}

}


mysql 数据中转工具类:

<?php
require_once SCRIPT_PATH.'/base/IndexDriver.php';
require_once SCRIPT_PATH.'/base/IndexField.php';
require_once SCRIPT_PATH.'/utils/Logger.php';

/**
* @author lx
* date: 2016-11-25
* transmit data from whatever source to mysql database.
*/
class MysqlTransmitter {

const DEBUG = true;

private $mysql_host;
private $mysql_port;
private $mysql_user;
private $mysql_password;
private $mysql_database;
private $mysqli;
private $value_query_step = 100;
private $value_insert_step = 10;

private $driver;
private $logger;

private $field_count;
private $mysql_insert_query_head;

public function __construct($driver) {
$this->logger = new Logger("MysqlTransmitter", Logger::LEVEL_DEBUG);
if (! $driver instanceof IndexDriver) {
$msg = "need a valid IndexDriver";
$this->logger->e($msg);
throw new Exception($msg);
}
$this->driver = $driver;
$this->field_count = count($driver->getIndexFields());
}

public function setMysqlHost($host, $port = null) {
$this->mysql_host = $host;
$this->mysql_port = $port;
return $this;
}

public function setMysqlUser($user, $password) {
$this->mysql_user = $user;
$this->mysql_password = $password;
return $this;
}

public function setMysqlDatabase($database) {
$this->mysql_database = $database;
return $this;
}

public function setValueQueryStep($step) {
$this->value_query_step = $step;
return $this;
}

public function setValueInsertStep($step) {
$this->value_insert_step = $step;
return $this;
}

public function transmit() {
// prepare mysql
$this->mysqlConnect();
$this->mysqlDropTable();
$this->mysqlCreateTable();

// fill data to mysql
$source_row_count = 0;
for ($i = 0; ; $i ++) {
// get values from whatever data source, with offset and limit
$offset = $i * $this->value_query_step;
$limit = $this->value_query_step;
$values = $this->driver->getValues($offset, $limit);
$value_count = count($values);
if ($value_count == 0) {
break;
}
$source_row_count += $value_count;
$this->logger->d("about to insert $value_count rows");
$this->mysqlInsertValues($values);
}

// check how many rows we've been inserted
$table_name = $this->driver->getIndexName();
$result= $this->mysqli->query("SELECT count(*) as total from $table_name");
$data = mysqli_fetch_assoc($result);
$this->logger->i("$table_name, insert result, ".
"$source_row_count rows from source, {$data['total']} rows to mysql");

$this->mysqli->close();
}

// ============================================

private function checkMysqlError() {
if ($this->mysqli->error) {
$this->logger->e("mysql error: {$this->mysqli->error}");
throw new Exception("MySQL error {$this->mysqli->error}", $this->msqli->errno);
}
}

private function mysqlConnect() {
$this->mysqli = new mysqli($this->mysql_host, $this->mysql_user, $this->mysql_password);
if ($this->mysqli->connect_error) {
throw new Exception("MySQL connect fail, " . $this->mysqli->connect_error);
}
$this->mysqli->query("CREATE DATABASE IF NOT EXISTS {$this->mysql_database}");
$this->mysqli->select_db($this->mysql_database);
$this->checkMysqlError();
$this->mysqli->query("SET NAMES UTF8");
$this->checkMysqlError();
}

private function mysqlDropTable() {
$table_name = $this->driver->getIndexName();
$this->mysqli->query("DROP TABLE IF EXISTS $table_name");
$this->checkMysqlError();
}

private function mysqlCreateTable() {
$table_name = $this->driver->getIndexName();
$fields = $this->driver->getIndexFields();
$create_query = "CREATE TABLE $table_name ( id int not null AUTO_INCREMENT, ";
foreach ($fields as $field) {
$create_query = $create_query
.$field->getName()." ".$field->getMysqlType()." null, ";
}
$create_query = $create_query . " PRIMARY KEY (id) ) DEFAULT CHARSET = 'UTF8'";
$this->logger->d("create query: $create_query");
$this->mysqli->query($create_query);
$this->checkMysqlError();
}

private function mysqlInsertQueryHead() {
if (!$this->mysql_insert_query_head) {
$fields = $this->driver->getIndexFields();
$table = $this->driver->getIndexName();
$this->mysql_insert_query_head = "INSERT INTO $table ( ";
for ($i = 0; $i < $this->field_count; $i ++) {
$field_name = $fields[$i]->getName();
$this->mysql_insert_query_head = $this->mysql_insert_query_head.$field_name;
if ($i + 1 < $this->field_count) {
$this->mysql_insert_query_head = $this->mysql_insert_query_head.", ";
} else {
$this->mysql_insert_query_head = $this->mysql_insert_query_head.") ";
}
}
}
return $this->mysql_insert_query_head;
}

private function mysqlInsertValues($values) {
// slice and insert values into mysql.
// mysql has a length limit for its sql sentence, while a value used for
// sphinx indexer is likely to be a long string. thus insert too much values
// in one sql sentence may result in a truncated sql sentence, so the values
// are sliced into sub arrays to do the insertion.
$step = $this->value_insert_step;
$fields = $this->driver->getIndexFields();
for ($j = 0; ; $j ++) {
$value_set = array_slice($values, $j * $step, $step);
$lines = count($value_set);
if ($lines == 0) {
break;
}
$insert_query = $this->mysqlInsertQueryHead()." VALUES ";
$valid_row_count = 0;
foreach ($value_set as $value) {
$value_query = "(";
$malformed = false;
for ($k = 0; $k < $this->field_count; $k ++) {
$v = $value[$fields[$k]->getName()];
if (empty($v)) {
$value_query = "$value_query ''";
} else if (!is_numeric($v)) {
// deal with the possible escape characters
$v_real = $this->mysqli->real_escape_string($v);
if (!$v_real) {
$this->logger->v("mysql insert value, malformed: $v");
$malformed = true;
}
$value_query = "$value_query '".$v_real."'";
} else {
$value_query = "$value_query $v";
}
if ($k + 1 < $this->field_count) {
$value_query = "$value_query , ";
} else {
$value_query = "$value_query ) ";
}
}
if ($malformed) {
$this->logger->e("mysql insert value fail, malformed. $value_query");
} else {
$this->logger->v("mysql insert value: $value_query");
$insert_query = "$insert_query $value_query ,";
$valid_row_count ++;
}
}

if ($valid_row_count > 0) {
$insert_query = substr($insert_query, 0, strlen($insert_query) - 1);
$this->logger->v("insert query: ".$insert_query);
$this->mysqli->query($insert_query);

if ($this->mysqli->error) {
$this->logger->e("insert error for: $insert_query");
$this->logger->e("insert error: {$this->mysqli->error}");
}
}
}
}

}

有了上面的一个 driver 和两个工具类,就可以写一个统一调度的 php 脚本.

统一调度脚本:

该脚本首先加载一个 config.ini 配置文件,所有sphinx目录等配置都是从这个ini文件读取的.

然后扫描 drivers 目录,将其中的 *Driver.php 文件加载进来.

然后调用上述两个工具类,完成 索引配置的生成 和 索引的建立.

其中将主动重建索引和由 crontab 发起的重建索引动作当做两个动作对待:

如果是由 crontab 发起的,则记录其重建时间,用以辅助判断下个 crontab 窗口是否要发起重建.

<?php
define('DEBUG', true);
define('APP_PATH', realpath(dirname(__FILE__)."/../.."));
define('SCRIPT_PATH', APP_PATH."/sphinx/script_php");
define('CONFIG_PATH', APP_PATH."/config/config.ini");
define('DRIVER_PATH', SCRIPT_PATH."/drivers/*Driver.php");
define('BASH_TOOL_PATH', APP_PATH."/sphinx/script_bash/sphinx_tool.sh");

require_once SCRIPT_PATH.'/utils/Logger.php';
require_once SCRIPT_PATH.'/utils/SphinxConfCreator.php';
require_once SCRIPT_PATH.'/utils/MysqlTransmitter.php';
require_once SCRIPT_PATH.'/utils/DocumentCreator.php';
foreach (glob(DRIVER_PATH) as $d) {
require_once $d;
}

/**
* h: print help
* c: rebuild sphinx config file.
* a: auto transmit index data to mysql. interval will be checked before transmit.
* t: transmit index data to mysql. a index name can be specified, or else all index data will be refreshed.
*/
$opts  = "hcar:";

// ============================================================

// get args
$args = getopt($opts);

if (isset($args['h'])) {
printHelp();
exit(0);
}

// read config file
$ini = parse_ini_file(CONFIG_PATH, true);
$pref_path = $ini['builder']['builder_pref_path'];

// init logger
Logger::init(APP_PATH."/".$ini["builder"]["builder_log_file"].".".date("Y-m"),
Logger::LEVEL_DEBUG, Logger::LEVEL_INFO);
Logger::ii("firing up !!!");

try {
// check mandatory dirs first
checkPreCreateDirs();

// load all driver files under driver path
$drivers = loadDrivers(DRIVER_PATH);

// check rebuild sphinx conf file
$conf_file_path = APP_PATH."/".$ini["sphinx"]["conf_file"];
if (isset($args['c']) || !file_exists($conf_file_path)) {
logi("rebuild sphinx conf");
rebuildSphinxConf($drivers);
}

$index_opt = "";
if (isset($args['r'])) {
$index_name = $args['r'];
if ($index_name == "--all") {
logi("transmit data for all indexes");
foreach ($drivers as $name => $driver) {
logi("transmit data for index: $name");
transmitDataToMysql($driver);
}
$index_opt = "--all";
} else {
// try refresh the specified index
if (isset($drivers[$index_name])) {
logi("transmit data for specified index: $index_name");
transmitDataToMysql($drivers[$index_name]);
$index_opt = $index_name;
} else {
logi("transmit data, unknown index: $index_name");
exit(1);
}
}

} else if (isset($args['a'])) {
logi("auto transmit data for all indexes");
foreach ($drivers as $name => $driver) {
if (isRequireAutoIndex($driver)) {
logi("auto transmit data for index: $name");
transmitDataToMysql($driver);
updateAutoIndexTime($driver);
$index_opt .= "$name ";
} else {
logi("auto transmit data for index: $name, interval not meet, ignore");
}
}
}

// if $index_opt is not empty, run sphinx indexer to refresh index
if (!empty($index_opt)) {
runIndexer($index_opt);
}

exit(0);
} catch (Exception $e) {
Logger::ee($e->getTraceAsString());
exit(1);
}

// ======================================================

function printHelp() {
echo <<<EOF

USAGE:

index_tool -a [-c]
重建索引.该用法主要用于 crontab 定时任务.上次更新时间,及 driver file 指定的重建间隔将被比较.
-c 参数指定重建 sphinx 索引配置文件.

index_tool -r index_name [-c]
重建指定索引.该用法用于手动更新索引,不会检查重建时间间隔.
-c 参数指定重建 sphinx 索引配置文件.

index_tool -r --all [-c]
重建全部索引.该用法用于手动更新索引,不会检查重建时间间隔.
-c 参数指定重建 sphinx 索引配置文件.

index_tool -c
重建索引配置文件.

DESCRIPTION:

用于根据 driver file, 重建索引 及 重建索引配置文件.
-a 参数用于 crontab 定时任务,在该参数下重建索引,会考虑 driver file 内指定的重建索引最小间隔参数.

EOF;
}

function logi($msg) {
//$GLOBALS['logger']->i($msg);
Logger::ii($msg, "index_tool");
}

function checkPreCreateDirs() {
$ini = $GLOBALS['ini'];
$sphinx_data_path = APP_PATH."/".$ini["sphinx"]["index_data_path"];
if (!file_exists($sphinx_data_path)) {
throw new Exception("pre-create dirs not ready !");
die();
}
}

function loadDrivers($driver_dir) {
$drivers = array();
foreach (glob($driver_dir) as $d) {
$splits = explode("/", $d);
$driver_name = chop($splits[count($splits) - 1], ".php");
$driver = new $driver_name;
if ($driver) {
$index_name = $driver->getIndexName();
$drivers[$index_name] = $driver;
logi("load driver: $index_name -> $d");
}
}
return $drivers;
}

function rebuildSphinxConf($drivers) {
$ini = $GLOBALS['ini'];
$conf_file_path = APP_PATH."/".$ini["sphinx"]["conf_file"];
if (file_exists($conf_file_path)) {
// backup conf file
$conf_file_bkp_name = basename($conf_file_path) .".". date("YmdHis");
$conf_file_bkp_path = APP_PATH."/".$ini['sphinx']['conf_bkp_path']."/".$conf_file_bkp_name;
copy($conf_file_path, $conf_file_bkp_path);
}

$sphinx_conf_creator = new SphinxConfCreator($drivers);
$sphinx_conf_creator
->setMysqlHost($ini["mysql"]["host"], $ini["mysql"]["port"])
->setMysqlUser($ini["mysql"]["user"], $ini["mysql"]["password"])
->setMysqlDatabase($ini["mysql"]["database"])
->setConfFilePath($conf_file_path)
->setConfCharsetDictPath($ini["sphinx"]["charset_dictpath"])
->setConfIndexDataPath(APP_PATH."/".$ini["sphinx"]["index_data_path"])
->setConfPidFilePath(APP_PATH."/".$ini["sphinx"]["pid_file"])
->setConfLogFilePath(APP_PATH."/".$ini["sphinx"]["log_file"])
->setConfQueryLogFilePath(APP_PATH."/".$ini["sphinx"]["query_log_file"])
->create();
}

function transmitDataToMysql($driver) {
$ini = $GLOBALS['ini'];
$transmitter = new MysqlTransmitter($driver);
$transmitter
->setMysqlHost($ini["mysql"]["host"], $ini["mysql"]["port"])
->setMysqlUser($ini["mysql"]["user"], $ini["mysql"]["password"])
->setMysqlDatabase($ini["mysql"]["database"])
->setValueQueryStep(200)
->setValueInsertStep(50)
->transmit();
}

function updateAutoIndexTime($driver) {
$pref_path = $GLOBALS['pref_path']."/".$driver->getIndexName()."_auto_index_time";
file_put_contents($pref_path, time() . "");
}

function isRequireAutoIndex($driver) {
$pref_path = $GLOBALS['pref_path']."/".$driver->getIndexName()."_auto_index_time";
$last_update_time = 0;
if (is_readable($pref_path)) {
$last_update_time = (int) file_get_contents($pref_path);
}
return $driver->shouldRefreshIndex($last_update_time);
}

function runIndexer($index_opt) {
$cmd = BASH_TOOL_PATH." $index_opt";
$output = shell_exec($cmd);
logi("bash: $cmd\n$output");
}

最后再由一个 bash 脚本负责调用 sphinx 的 searchd 命令建立索引.
这个简单,就是个壳而已,不再贴出.

最最后,贴一下 config.ini 配置文件,以便阅读:

# author: lx
# setup.sh will create parent dirs for configs with name ends with _file;
# setup.sh will create dirs for configs with name ends with _path.

[mysql]
host = 127.0.0.1
port = 3306
user = root
password = xxxxxxxxx
database = sphinx_source

[mongo]
host = 127.0.0.1
port = 27017

[sphinx]
host = 127.0.0.1
port = 9312
searchd = /usr/local/coreseek/bin/searchd
indexer = /usr/local/coreseek/bin/indexer
charset_dictpath = /usr/local/mmseg3/etc/
conf_file = var/sphinx/index.conf
index_data_path = var/sphinx/data
pid_file = var/sphinx/searchd.pid
log_file = var/sphinx/logs/searchd.log
query_log_file = var/sphinx/logs/searchd_query.log
conf_bkp_path = var/sphinx/index_backup

[builder]
php_bin = /usr/local/php/bin/php
builder_log_file = var/builder/logs/builder.log
builder_pref_path = var/builder/preferences

[request]
request_log_file = var/request/logs/request.log

最最最后,一个根据上述配置文件建立预设目录的脚本.
规则是,上述配置文件中字段名以 _file 结尾的,则建立其父目录; 以 _path 结尾的,则建立其目录.

#!/bin/bash

# author : liuxu
# date   : 2016-12-23

PROJ_PATH=$(dirname $(git rev-parse --git-dir))
CONF_FILE=$PROJ_PATH/config/config.ini

if [ -e $CONF_FILE ]; then

paths=$(sed -n "/\w\+_path\s*=.*/"p $CONF_FILE | sed 's/[[:space:]]\+//g' | awk -F "=" '{print $2}')
files=$(sed -n "/\w\+_file\s*=.*/"p $CONF_FILE | sed 's/[[:space:]]\+//g' | awk -F "=" '{print $2}')

cd $PROJ_PATH

for p in ${paths[*]}; do
mkdir -vp $PROJ_PATH/$p
done

for f in ${files[*]}; do
d=$(dirname $PROJ_PATH/$f)
mkdir -vp $d
done
cd -

else
echo "* config.ini not exists."
fi
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  sphinx mongodb