1
0
mirror of https://gitee.com/koogua/course-tencent-cloud.git synced 2025-08-01 04:18:09 +08:00

去除user全文索引相关

This commit is contained in:
koogua 2022-09-06 17:30:06 +08:00
parent 93ec72faf6
commit b79d6e5588
16 changed files with 8 additions and 638 deletions

1
.gitignore vendored
View File

@ -5,7 +5,6 @@
/config/xs.course.ini
/config/xs.article.ini
/config/xs.question.ini
/config/xs.user.ini
/config/alipay/*.crt
/config/wxpay/*.pem
/db/migrations/schema.php

View File

@ -106,9 +106,6 @@ class CleanDemoDataTask extends Task
$questionIndexTask = new QuestionIndexTask();
$questionIndexTask->cleanAction();
$userIndexTask = new UserIndexTask();
$userIndexTask->cleanAction();
}
protected function isDemoEnv()

View File

@ -1,65 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
* @license https://opensource.org/licenses/GPL-2.0
* @link https://www.koogua.com
*/
namespace App\Console\Tasks;
use App\Repos\User as UserRepo;
use App\Services\Search\UserDocument;
use App\Services\Search\UserSearcher;
use App\Services\Sync\UserIndex as UserIndexSync;
class SyncUserIndexTask extends Task
{
public function mainAction()
{
$redis = $this->getRedis();
$key = $this->getSyncKey();
$userIds = $redis->sRandMember($key, 1000);
if (!$userIds) return;
$userRepo = new UserRepo();
$users = $userRepo->findByIds($userIds);
if ($users->count() == 0) return;
$document = new UserDocument();
$handler = new UserSearcher();
$index = $handler->getXS()->getIndex();
$index->openBuffer();
foreach ($users as $user) {
$doc = $document->setDocument($user);
if ($user->deleted == 0) {
$index->update($doc);
} else {
$index->del($user->id);
}
}
$index->closeBuffer();
$redis->sRem($key, ...$userIds);
}
protected function getSyncKey()
{
$sync = new UserIndexSync();
return $sync->getSyncKey();
}
}

View File

@ -1,154 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
* @license https://opensource.org/licenses/GPL-2.0
* @link https://www.koogua.com
*/
namespace App\Console\Tasks;
use App\Models\User as UserModel;
use App\Repos\User as UserRepo;
use App\Services\Search\UserDocument;
use App\Services\Search\UserSearcher;
use Phalcon\Mvc\Model\Resultset;
use Phalcon\Mvc\Model\ResultsetInterface;
class UserIndexTask extends Task
{
/**
* 搜索测试
*
* @command: php console.php user_index search {query}
* @param array $params
* @throws \XSException
*/
public function searchAction($params)
{
$query = $params[0] ?? null;
if (!$query) {
exit('please special a query word' . PHP_EOL);
}
$result = $this->searchUsers($query);
var_export($result);
}
/**
* 清空索引
*
* @command: php console.php user_index clean
*/
public function cleanAction()
{
$this->cleanUserIndex();
}
/**
* 重建索引
*
* @command: php console.php user_index rebuild
*/
public function rebuildAction()
{
$this->rebuildUserIndex();
}
/**
* 清空索引
*/
protected function cleanUserIndex()
{
$handler = new UserSearcher();
$index = $handler->getXS()->getIndex();
echo '------ start clean user index ------' . PHP_EOL;
$index->clean();
echo '------ end clean user index ------' . PHP_EOL;
}
/**
* 重建索引
*/
protected function rebuildUserIndex()
{
$limit = 1000;
$totalCount = $this->countUsers();
if ($totalCount == 0) return;
$page = ceil($totalCount / $limit);
$handler = new UserSearcher();
$documenter = new UserDocument();
$index = $handler->getXS()->getIndex();
echo '------ start rebuild user index ------' . PHP_EOL;
$index->beginRebuild();
for ($i = 0; $i < $page; $i++) {
$offset = $i * $limit;
$users = $this->findUsers($limit, $offset);
if ($users->count() == 0) break;
foreach ($users as $user) {
$document = $documenter->setDocument($user);
$index->add($document);
}
echo "------ fetch users: {$limit},{$offset} ------" . PHP_EOL;
}
$index->endRebuild();
echo '------ end rebuild user index ------' . PHP_EOL;
}
/**
* 搜索课程
*
* @param string $query
* @return array
* @throws \XSException
*/
protected function searchUsers($query)
{
$handler = new UserSearcher();
return $handler->search($query);
}
/**
* @param int $limit
* @param int $offset
* @return ResultsetInterface|Resultset|UserModel[]
*/
protected function findUsers($limit, $offset)
{
return UserModel::query()
->where('deleted = 0')
->limit($limit, $offset)
->execute();
}
protected function countUsers()
{
$userRepo = new UserRepo();
return $userRepo->countUsers();
}
}

View File

@ -9,9 +9,7 @@ namespace App\Http\Api\Controllers;
use App\Services\Logic\Search\Article as ArticleSearch;
use App\Services\Logic\Search\Course as CourseSearch;
use App\Services\Logic\Search\Group as GroupSearch;
use App\Services\Logic\Search\Question as QuestionSearch;
use App\Services\Logic\Search\User as UserSearch;
/**
* @RoutePrefix("/api/search")
@ -46,7 +44,7 @@ class SearchController extends Controller
/**
* @param string $type
* @return ArticleSearch|QuestionSearch|CourseSearch|GroupSearch|UserSearch
* @return ArticleSearch|QuestionSearch|CourseSearch
*/
protected function getSearchService($type)
{
@ -57,12 +55,6 @@ class SearchController extends Controller
case 'question':
$service = new QuestionSearch();
break;
case 'group':
$service = new GroupSearch();
break;
case 'user':
$service = new UserSearch();
break;
default:
$service = new CourseSearch();
break;

View File

@ -9,9 +9,7 @@ namespace App\Http\Home\Controllers;
use App\Services\Logic\Search\Article as ArticleSearchService;
use App\Services\Logic\Search\Course as CourseSearchService;
use App\Services\Logic\Search\Group as GroupSearchService;
use App\Services\Logic\Search\Question as QuestionSearchService;
use App\Services\Logic\Search\User as UserSearchService;
/**
* @RoutePrefix("/search")
@ -48,7 +46,7 @@ class SearchController extends Controller
/**
* @param string $type
* @return ArticleSearchService|QuestionSearchService|CourseSearchService|GroupSearchService|UserSearchService
* @return ArticleSearchService|QuestionSearchService|CourseSearchService
*/
protected function getSearchService($type)
{
@ -59,12 +57,6 @@ class SearchController extends Controller
case 'question':
$service = new QuestionSearchService();
break;
case 'group':
$service = new GroupSearchService();
break;
case 'user':
$service = new UserSearchService();
break;
default:
$service = new CourseSearchService();
break;

View File

@ -4,7 +4,7 @@
{{ partial('macros/course') }}
{% set types = {'course':'课程','article':'专栏','question':'问答','user':'用户'} %}
{% set types = {'course':'课程','article':'专栏','question':'问答'} %}
{% set type = request.get('type','trim','course') %}
{% set query = request.get('query','striptags','') %}
@ -39,10 +39,6 @@
<div class="layui-tab-item layui-show">
{{ partial('search/question') }}
</div>
{% elseif type == 'user' %}
<div class="layui-tab-item layui-show">
{{ partial('search/user') }}
</div>
{% endif %}
</div>
</div>

View File

@ -1,29 +0,0 @@
{{ partial('macros/user') }}
{% if pager.total_pages > 0 %}
<div class="search-user-list">
{% for item in pager.items %}
{% set user_url = url({'for':'home.user.show','id':item.id}) %}
{% set item.about = item.about|default('这个家伙真懒,什么也没有留下!') %}
<div class="search-user-card">
<div class="avatar">
<a href="{{ user_url }}" target="_blank">
<img src="{{ item.avatar }}!avatar_160" alt="{{ item.name }}">
</a>
</div>
<div class="info">
<div class="name">
<a href="{{ user_url }}" target="_blank">{{ item.name }}</a>
</div>
<div class="about">{{ item.about }}</div>
<div class="meta">
<span>性别:{{ gender_info(item.gender) }}</span>
<span>地区:{{ item.area }}</span>
</div>
</div>
</div>
{% endfor %}
</div>
{% else %}
{{ partial('search/empty') }}
{% endif %}

View File

@ -9,7 +9,6 @@ namespace App\Models;
use App\Caches\MaxUserId as MaxUserIdCache;
use App\Caches\User as UserCache;
use App\Services\Sync\UserIndex as UserIndexSync;
use Phalcon\Mvc\Model\Behavior\SoftDelete;
use Phalcon\Text;
@ -216,11 +215,6 @@ class User extends Model
public function beforeUpdate()
{
if (time() - $this->update_time > 3 * 3600) {
$sync = new UserIndexSync();
$sync->addItem($this->id);
}
$this->update_time = time();
}

View File

@ -1,90 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
* @license https://opensource.org/licenses/GPL-2.0
* @link https://www.koogua.com
*/
namespace App\Services\Logic\Search;
use App\Library\Paginator\Adapter\XunSearch as XunSearchPaginator;
use App\Library\Paginator\Query as PagerQuery;
use App\Services\Search\GroupSearcher as GroupSearcherService;
use Phalcon\Text;
class Group extends Handler
{
public function search()
{
$pagerQuery = new PagerQuery();
$params = $pagerQuery->getParams();
$page = $pagerQuery->getPage();
$limit = $pagerQuery->getLimit();
$searcher = new GroupSearcherService();
$paginator = new XunSearchPaginator([
'xs' => $searcher->getXS(),
'highlight' => $searcher->getHighlightFields(),
'query' => $params['query'],
'page' => $page,
'limit' => $limit,
]);
$pager = $paginator->getPaginate();
return $this->handleGroups($pager);
}
public function getHotQuery($limit = 10, $type = 'total')
{
$searcher = new GroupSearcherService();
return $searcher->getHotQuery($limit, $type);
}
public function getRelatedQuery($query, $limit = 10)
{
$searcher = new GroupSearcherService();
return $searcher->getRelatedQuery($query, $limit);
}
protected function handleGroups($pager)
{
if ($pager->total_items == 0) {
return $pager;
}
$items = [];
$baseUrl = kg_cos_url();
foreach ($pager->items as $item) {
$owner = json_decode($item['owner'], true);
if (!empty($item['avatar']) && !Text::startsWith($item['avatar'], 'http')) {
$item['avatar'] = $baseUrl . $item['avatar'];
}
$items[] = [
'id' => (int)$item['id'],
'type' => (int)$item['type'],
'name' => (string)$item['name'],
'avatar' => (string)$item['avatar'],
'about' => (string)$item['about'],
'user_count' => (int)$item['user_count'],
'msg_count' => (int)$item['msg_count'],
'owner' => $owner,
];
}
$pager->items = $items;
return $pager;
}
}

View File

@ -1,85 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
* @license https://opensource.org/licenses/GPL-2.0
* @link https://www.koogua.com
*/
namespace App\Services\Logic\Search;
use App\Library\Paginator\Adapter\XunSearch as XunSearchPaginator;
use App\Library\Paginator\Query as PagerQuery;
use App\Services\Search\UserSearcher as UserSearcherService;
class User extends Handler
{
public function search()
{
$pagerQuery = new PagerQuery();
$params = $pagerQuery->getParams();
$page = $pagerQuery->getPage();
$limit = $pagerQuery->getLimit();
$searcher = new UserSearcherService();
$paginator = new XunSearchPaginator([
'xs' => $searcher->getXS(),
'highlight' => $searcher->getHighlightFields(),
'query' => $params['query'],
'page' => $page,
'limit' => $limit,
]);
$pager = $paginator->getPaginate();
return $this->handleUsers($pager);
}
public function getHotQuery($limit = 10, $type = 'total')
{
$searcher = new UserSearcherService();
return $searcher->getHotQuery($limit, $type);
}
public function getRelatedQuery($query, $limit = 10)
{
$searcher = new UserSearcherService();
return $searcher->getRelatedQuery($query, $limit);
}
protected function handleUsers($pager)
{
if ($pager->total_items == 0) {
return $pager;
}
$items = [];
$baseUrl = kg_cos_url();
foreach ($pager->items as $item) {
$item['avatar'] = $baseUrl . $item['avatar'];
$items[] = [
'id' => (int)$item['id'],
'name' => (string)$item['name'],
'avatar' => (string)$item['avatar'],
'title' => (string)$item['title'],
'about' => (string)$item['about'],
'vip' => (int)$item['vip'],
'gender' => (int)$item['gender'],
'area' => (string)$item['area'],
];
}
$pager->items = $items;
return $pager;
}
}

View File

@ -1,55 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
* @license https://opensource.org/licenses/GPL-2.0
* @link https://www.koogua.com
*/
namespace App\Services\Search;
use App\Models\User as UserModel;
use Phalcon\Di\Injectable;
class UserDocument extends Injectable
{
/**
* 设置文档
*
* @param UserModel $user
* @return \XSDocument
*/
public function setDocument(UserModel $user)
{
$doc = new \XSDocument();
$data = $this->formatDocument($user);
$doc->setFields($data);
return $doc;
}
/**
* 格式化文档
*
* @param UserModel $user
* @return array
*/
public function formatDocument(UserModel $user)
{
$user->avatar = UserModel::getAvatarPath($user->avatar);
return [
'id' => $user->id,
'name' => $user->name,
'title' => $user->title,
'avatar' => $user->avatar,
'about' => $user->about,
'gender' => $user->gender,
'area' => $user->area,
'vip' => $user->vip,
];
}
}

View File

@ -1,30 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
* @license https://opensource.org/licenses/GPL-2.0
* @link https://www.koogua.com
*/
namespace App\Services\Search;
class UserSearcher extends Searcher
{
public function __construct()
{
$this->xs = $this->getXS();
}
public function getXS()
{
$filename = config_path('xs.user.ini');
return new \XS($filename);
}
public function getHighlightFields()
{
return ['name', 'about'];
}
}

View File

@ -1,38 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
* @license https://opensource.org/licenses/GPL-2.0
* @link https://www.koogua.com
*/
namespace App\Services\Sync;
use App\Services\Service;
class UserIndex extends Service
{
/**
* @var int
*/
protected $lifetime = 86400;
public function addItem($userId)
{
$redis = $this->getRedis();
$key = $this->getSyncKey();
$redis->sAdd($key, $userId);
if ($redis->sCard($key) == 1) {
$redis->expire($key, $this->lifetime);
}
}
public function getSyncKey()
{
return 'sync_user_index';
}
}

View File

@ -1,32 +0,0 @@
project.name = user
project.default_charset = UTF-8
server.index = xunsearch:8383
server.search = xunsearch:8384
[id]
type = id
[name]
type = title
[avatar]
type = string
[title]
type = string
[about]
type = body
[area]
type = string
index = self
[gender]
type = string
index = self
tokenizer = full
[vip]
type = string

View File

@ -353,16 +353,14 @@
}
.search-course-card,
.search-article-card,
.search-user-card {
.search-article-card {
display: flex;
padding-bottom: 15px;
margin-bottom: 15px;
border-bottom: 1px solid #f6f6f6;
}
.search-course-card:last-child,
.search-user-card:last-child {
.search-course-card:last-child {
padding-bottom: 0;
margin-bottom: 0;
border: none;
@ -374,8 +372,7 @@
margin-right: 15px;
}
.search-course-card .cover img,
.search-user-card .avatar img {
.search-course-card .cover img {
width: 100%;
height: 100%;
}
@ -384,14 +381,12 @@
width: 500px;
}
.search-course-card .title,
.search-user-card .name {
.search-course-card .title {
margin-bottom: 10px;
white-space: nowrap;
}
.search-course-card .summary,
.search-user-card .about {
.search-course-card .summary {
margin-bottom: 10px;
line-height: 1.5em;
max-height: 4.5em;
@ -401,41 +396,24 @@
}
.search-course-card .meta,
.search-user-card .meta,
.search-article-card .meta,
.search-question-card .meta {
color: #999;
}
.search-course-card .meta span,
.search-user-card .meta span,
.search-article-card .meta span,
.search-question-card .meta span {
margin-right: 10px;
}
.search-course-card em,
.search-user-card em,
.search-article-card em,
.search-question-card em {
color: red;
font-style: normal;
}
.search-user-card .avatar {
width: 90px;
height: 90px;
margin-right: 15px;
}
.search-user-card .avatar img {
border-radius: 100%;
}
.search-user-card .info {
width: 600px;
}
.query-badge {
padding: 2px 5px;
margin-right: 5px;