Explorar o código

:construction: create

visuddhinanda %!s(int64=3) %!d(string=hai) anos
pai
achega
84ed059c3f

+ 57 - 0
app/Console/Commands/UpgradeFts.php

@@ -0,0 +1,57 @@
+<?php
+
+namespace App\Console\Commands;
+
+use Illuminate\Console\Command;
+use App\Models\BookTitle;
+use App\Models\FtsText;
+
+class UpgradeFts extends Command
+{
+    /**
+     * The name and signature of the console command.
+     *
+     * @var string
+     */
+    protected $signature = 'upgrade:fts {--book}';
+
+    /**
+     * The console command description.
+     *
+     * @var string
+     */
+    protected $description = 'Command description';
+
+    /**
+     * Create a new command instance.
+     *
+     * @return void
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * Execute the console command.
+     *
+     * @return int
+     */
+    public function handle()
+    {
+        if($this->option('book')){
+            $bookTitles = BookTitle::orderBy('id')->get();
+            $bar = $this->output->createProgressBar(count($bookTitles));
+            foreach ($bookTitles as $key => $value) {
+                # code...
+                FtsText::where('book',$value->book)
+                        ->where('paragraph','>=',$value->paragraph)
+                        ->update(['pcd_book_id'=>$value->id]);
+                $bar->advance();
+            }
+            $bar->finish();
+            return 0;
+        }
+        return 0;
+    }
+}

+ 261 - 0
app/Http/Controllers/SearchController.php

@@ -0,0 +1,261 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use Illuminate\Http\Request;
+use App\Models\BookTitle;
+use App\Models\FtsText;
+use App\Models\Tag;
+use App\Models\TagMap;
+use App\Models\PaliText;
+use Illuminate\Support\Facades\Http;
+use Illuminate\Support\Facades\DB;
+use App\Http\Resources\SearchResource;
+use App\Http\Resources\SearchBookResource;
+use Illuminate\Support\Facades\Log;
+use App\Tools\Tools;
+
+
+class SearchController extends Controller
+{
+    /**
+     * Display a listing of the resource.
+     *
+     * @return \Illuminate\Http\Response
+     */
+    public function index(Request $request)
+    {
+        //
+        $searchChapters = [];
+        $searchBooks = [];
+        $searchBookId = [];
+        $queryBookId = '';
+
+        if($request->has('book')){
+            $queryBookId = ' AND pcd_book_id = ' . (int)$request->get('book');
+        }else if($request->has('tags')){
+            //查询搜索范围
+            $tags = explode(',',$request->get('tags'));
+            $tagIds = Tag::whereIn('name',$tags)->select('id')->get();
+            $paliTextIds = TagMap::where('table_name','pali_texts')->whereIn('tag_id',$tagIds)->select('anchor_id')->get();
+            $paliPara=[];
+            foreach ($paliTextIds as $key => $value) {
+                # code...
+                if(isset($paliPara[$value->anchor_id])){
+                    $paliPara[$value->anchor_id]++;
+                }else{
+                    $paliPara[$value->anchor_id]=1;
+                }
+            }
+            $paliId=[];
+            foreach ($paliPara as $key => $value) {
+                # code...
+                if($value===count($tags)){
+                    $paliId[] = $key;
+                }
+            }
+            $para = PaliText::where('level',1)->whereIn('uid',$paliId)->get();
+            Log::info($para);
+
+            if(count($para)>0){
+                foreach ($para as $key => $value) {
+                    # code...
+                    $book_id = BookTitle::where('book',$value['book'])->where('paragraph',$value['paragraph'])->value('id');
+                    if(!empty($book_id)){
+                        $searchBookId[] = $book_id;
+                    }
+                    $searchChapters[] = ['book'=>$value['book'],'paragraph'=>$value['paragraph']];
+                }
+                $queryBookId = ' AND pcd_book_id in ('.implode(',',$searchBookId).') ';
+            }
+        }
+
+        $key = $request->get('key');
+        $param = [];
+        switch ($request->get('match','case')) {
+            case 'complete':
+                # code...
+                $querySelect_rank = "
+                ts_rank('{0.1, 0.2, 0.4, 1}',
+                    full_text_search_weighted,
+                    websearch_to_tsquery('pali', ?))
+                AS rank, ";
+                $querySelect_highlight = " ts_headline('pali', content,
+                websearch_to_tsquery('pali', ?),
+                'StartSel = ~~, StopSel = ~~,MaxWords=3500, MinWords=3500,HighlightAll=TRUE')
+                AS highlight,";
+                $queryWhere = " full_text_search_weighted @@ websearch_to_tsquery('pali', ?) ";
+                $param = [$key,$key,$key];
+                break;
+            case 'case':
+                # code...
+                $querySelect_rank = "
+                ts_rank('{0.1, 0.2, 0.4, 1}',
+                    full_text_search_weighted,
+                    websearch_to_tsquery('pali', ?))
+                AS rank, ";
+                $querySelect_highlight = " ts_headline('pali', content,
+                websearch_to_tsquery('pali', ?),
+                'StartSel = ~~, StopSel = ~~,MaxWords=3500, MinWords=3500,HighlightAll=TRUE')
+                AS highlight,";
+                $queryWhere = " full_text_search_weighted @@ websearch_to_tsquery('pali', ?) ";
+                $param = [$key,$key,$key];
+                break;
+            case 'similar':
+                # 形似,去掉变音符号
+
+                $querySelect_rank = "
+                    ts_rank('{0.1, 0.2, 0.4, 1}',
+                        full_text_search_weighted_unaccent,
+                        websearch_to_tsquery('pali_unaccent', ?))
+                    AS rank, ";
+                    $querySelect_highlight = " ts_headline('pali_unaccent', content,
+                        websearch_to_tsquery('pali_unaccent', ?),
+                        'StartSel = ~~, StopSel = ~~,MaxWords=3500, MinWords=3500,HighlightAll=TRUE')
+                        AS highlight,";
+                $queryWhere = " full_text_search_weighted_unaccent @@ websearch_to_tsquery('pali_unaccent', ?) ";
+                $key = Tools::getWordEn($key);
+                $param = [$key,$key,$key];
+                break;
+        }
+
+
+        $querySelect_2 = "  book,paragraph,content ";
+
+
+
+        $queryCount = "SELECT count(*) as co FROM fts_texts WHERE {$queryWhere} {$queryBookId};";
+        $resultCount = DB::select($queryCount, [$key]);
+
+        $limit = $request->get('limit',10);
+        $offset = $request->get('offset',0);
+        switch ( $request->get('orderby',"rank")) {
+            case 'rank':
+                $orderby = " ORDER BY rank DESC ";
+                break;
+            case 'paragraph':
+                $orderby = " ORDER BY book,paragraph ";
+                break;
+            default:
+                $orderby = "";
+                break;
+        };
+        $query = "SELECT
+            {$querySelect_rank}
+            {$querySelect_highlight}
+            {$querySelect_2}
+            FROM fts_texts
+            WHERE
+                {$queryWhere}
+                {$queryBookId}
+                {$orderby}
+            LIMIT ? OFFSET ? ;";
+        $param[] = $limit;
+        $param[] = $offset;
+
+        $result = DB::select($query, $param);
+
+        //待查询单词列表
+        //$caseMan = new CaseMan();
+        //$wordSpell = $caseMan->BaseToWord($key);
+
+        return $this->ok(["rows"=>SearchResource::collection($result),"count"=>$resultCount[0]->co]);
+    }
+
+    public function book_list(Request $request){
+        $searchChapters = [];
+        $searchBooks = [];
+        $searchBookId = [];
+        $queryBookId = '';
+
+        if($request->has('tags')){
+            //查询搜索范围
+            $tags = explode(',',$request->get('tags'));
+            $tagIds = Tag::whereIn('name',$tags)->select('id')->get();
+            $paliTextIds = TagMap::where('table_name','pali_texts')->whereIn('tag_id',$tagIds)->select('anchor_id')->get();
+            $paliPara=[];
+            foreach ($paliTextIds as $key => $value) {
+                # code...
+                if(isset($paliPara[$value->anchor_id])){
+                    $paliPara[$value->anchor_id]++;
+                }else{
+                    $paliPara[$value->anchor_id]=1;
+                }
+            }
+            $paliId=[];
+            foreach ($paliPara as $key => $value) {
+                # code...
+                if($value===count($tags)){
+                    $paliId[] = $key;
+                }
+            }
+            $para = PaliText::where('level',1)->whereIn('uid',$paliId)->get();
+            Log::info($para);
+
+            if(count($para)>0){
+                foreach ($para as $key => $value) {
+                    # code...
+                    $book_id = BookTitle::where('book',$value['book'])->where('paragraph',$value['paragraph'])->value('id');
+                    if(!empty($book_id)){
+                        $searchBookId[] = $book_id;
+                    }
+                    $searchChapters[] = ['book'=>$value['book'],'paragraph'=>$value['paragraph']];
+                }
+                $queryBookId = ' AND pcd_book_id in ('.implode(',',$searchBookId).') ';
+            }
+        }
+        $key = $request->get('key');
+
+        $queryWhere = "( full_text_search_weighted @@ websearch_to_tsquery('pali', ?) OR
+        full_text_search_weighted_unaccent @@ websearch_to_tsquery('pali_unaccent', ?) )";
+
+        $query = "SELECT pcd_book_id, count(*) as co FROM fts_texts WHERE {$queryWhere} {$queryBookId} GROUP BY pcd_book_id ORDER BY co DESC;";
+        $result = DB::select($query, [$key,$key]);
+
+        return $this->ok(["rows"=>SearchBookResource::collection($result),"count"=>count($result)]);
+    }
+    /**
+     * Store a newly created resource in storage.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @return \Illuminate\Http\Response
+     */
+    public function store(Request $request)
+    {
+        //
+    }
+
+    /**
+     * Display the specified resource.
+     *
+     * @param  int  $id
+     * @return \Illuminate\Http\Response
+     */
+    public function show($id)
+    {
+        //
+    }
+
+    /**
+     * Update the specified resource in storage.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @param  int  $id
+     * @return \Illuminate\Http\Response
+     */
+    public function update(Request $request, $id)
+    {
+        //
+    }
+
+    /**
+     * Remove the specified resource from storage.
+     *
+     * @param  int  $id
+     * @return \Illuminate\Http\Response
+     */
+    public function destroy($id)
+    {
+        //
+    }
+}

+ 81 - 0
app/Http/Controllers/WordIndexController.php

@@ -0,0 +1,81 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use App\Models\WordIndex;
+use Illuminate\Http\Request;
+use App\Http\Resources\WordIndexResource;
+use Illuminate\Support\Facades\Cache;
+
+class WordIndexController extends Controller
+{
+    /**
+     * Display a listing of the resource.
+     *
+     * @return \Illuminate\Http\Response
+     */
+    public function index(Request $request)
+    {
+        //
+        switch ($request->get("view")) {
+            case 'key':
+                $key = $request->get("key");
+                $result = Cache::remember("/word_index/{$key}",120,function() use($key){
+                    return WordIndex::where('word','like',$key."%")
+                                    ->whereOr('word_en','like',$key."%")
+                                    ->orderBy('word')
+                                    ->take(10)->get();
+                });
+                return $this->ok(['rows'=>WordIndexResource::collection($result),'count'=>count($result)]);
+                break;
+            default:
+                return $this->error('view error');
+                break;
+        }
+    }
+
+    /**
+     * Store a newly created resource in storage.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @return \Illuminate\Http\Response
+     */
+    public function store(Request $request)
+    {
+        //
+    }
+
+    /**
+     * Display the specified resource.
+     *
+     * @param  \App\Models\WordIndex  $wordIndex
+     * @return \Illuminate\Http\Response
+     */
+    public function show(WordIndex $wordIndex)
+    {
+        //
+    }
+
+    /**
+     * Update the specified resource in storage.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @param  \App\Models\WordIndex  $wordIndex
+     * @return \Illuminate\Http\Response
+     */
+    public function update(Request $request, WordIndex $wordIndex)
+    {
+        //
+    }
+
+    /**
+     * Remove the specified resource from storage.
+     *
+     * @param  \App\Models\WordIndex  $wordIndex
+     * @return \Illuminate\Http\Response
+     */
+    public function destroy(WordIndex $wordIndex)
+    {
+        //
+    }
+}

+ 29 - 0
app/Http/Resources/SearchBookResource.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Illuminate\Http\Resources\Json\JsonResource;
+use App\Models\BookTitle;
+use App\Models\PaliText;
+
+class SearchBookResource extends JsonResource
+{
+    /**
+     * Transform the resource into an array.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
+     */
+    public function toArray($request)
+    {
+        $book = BookTitle::find($this->pcd_book_id);
+        $toc = PaliText::where('book',$book->book)->where("paragraph",$book->paragraph)->value('toc');
+        return [
+            "book"=>$book->book,
+            "paragraph"=> $book->paragraph,
+            "paliTitle"=> $toc,
+            'pcdBookId'=>$this->pcd_book_id,
+            "count"=>$this->co,
+        ];
+    }
+}

+ 42 - 0
app/Http/Resources/SearchResource.php

@@ -0,0 +1,42 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Illuminate\Http\Resources\Json\JsonResource;
+use App\Models\PaliText;
+
+class SearchResource extends JsonResource
+{
+    /**
+     * Transform the resource into an array.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
+     */
+    public function toArray($request)
+    {
+        $data = [
+            "book"=>$this->book,
+            "paragraph"=> $this->paragraph,
+            "content"=> $this->content,
+            "rank"=> $this->rank,
+            "highlight"=> $this->highlight,
+        ];
+
+        $paliText = PaliText::where('book',$this->book)
+                            ->where('paragraph',$this->paragraph)
+                            ->first();
+        if($paliText){
+            $data['path'] = json_decode($paliText->path);
+            if($paliText->level<100){
+                $data["paliTitle"] = $paliText->toc;
+            }else{
+                $data["paliTitle"] = PaliText::where('book',$this->book)
+                                            ->where('paragraph',$paliText->parent)
+                                            ->value('toc');
+            }
+
+        }
+        return $data;
+    }
+}

+ 19 - 0
app/Http/Resources/WordIndexResource.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace App\Http\Resources;
+
+use Illuminate\Http\Resources\Json\JsonResource;
+
+class WordIndexResource extends JsonResource
+{
+    /**
+     * Transform the resource into an array.
+     *
+     * @param  \Illuminate\Http\Request  $request
+     * @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
+     */
+    public function toArray($request)
+    {
+        return parent::toArray($request);
+    }
+}

+ 34 - 0
database/migrations/2023_03_29_132614_add_pcd_book_in_fts_texts.php

@@ -0,0 +1,34 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class AddPcdBookInFtsTexts extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('fts_texts', function (Blueprint $table) {
+            //
+            $table->integer('pcd_book_id')->index()->default(0);
+
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('fts_texts', function (Blueprint $table) {
+            $table->dropColumn('pcd_book_id');
+        });
+    }
+}

+ 29 - 0
tests/Feature/SearchTest.php

@@ -0,0 +1,29 @@
+<?php
+
+namespace Tests\Feature;
+
+use Illuminate\Foundation\Testing\RefreshDatabase;
+use Illuminate\Foundation\Testing\WithFaker;
+use Tests\TestCase;
+
+class SearchTest extends TestCase
+{
+    /**
+     * A basic feature test example.
+     *
+     * @return void
+     */
+    public function test_index()
+    {
+        $response = $this->get('/api/v2/search?key=samānasaṃvāsa&tags=sutta');
+
+        $response->assertStatus(200);
+    }
+    public function test_book_list()
+    {
+        $response = $this->get('/api/v2/search-book-list?key=samānasaṃvāsa&tags=sutta');
+
+        $response->assertStatus(200);
+    }
+
+}

+ 22 - 0
tests/Feature/WordIndexTest.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace Tests\Feature;
+
+use Illuminate\Foundation\Testing\RefreshDatabase;
+use Illuminate\Foundation\Testing\WithFaker;
+use Tests\TestCase;
+
+class WordIndexTest extends TestCase
+{
+    /**
+     * A basic feature test example.
+     *
+     * @return void
+     */
+    public function test_index()
+    {
+        $response = $this->get('/api/v2/pali-word-index?view=key&key=a');
+
+        $response->assertStatus(200);
+    }
+}