Skip to content

Commit

Permalink
feat: support slqite index engine
Browse files Browse the repository at this point in the history
  • Loading branch information
terasum committed Oct 22, 2023
1 parent 8b085d4 commit b64c863
Show file tree
Hide file tree
Showing 18 changed files with 606 additions and 73 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
dev:
wails dev --loglevel info
build:
wails build -devtools
wails build

license:
addlicense -c "Quan Chen <chenquan_act@163.com>" -l gpl3 -v -y 2023 -ignore frontend/**/* -ignore build/**/* -ignore .github/**/* frontend/src
Expand All @@ -11,4 +11,4 @@ create-dmg:



.PHONY: build license
.PHONY: build license
43 changes: 36 additions & 7 deletions frontend/src/view/main/MainRightToolbar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -136,19 +136,48 @@ function loadDictionaries() {
const totalNumber = res.length;
const updater = updateProgress(totalNumber);
for (let i = 0; i < res.length; i++) {
state.dictList.push(res[i]);
console.log(`[app-init] building dictionary, index: ${i}`, res[i])
function sequenceHandle(promiseArr) {
const pro = promiseArr.shift()
if(pro && pro.handle) {
pro.handle().then((resp)=>{
pro.callback(resp);
sequenceHandle(promiseArr)
})
}
}
BuildIndex(res[i].id).then((resp) => {
let progressHint = `词典 ${res[i].name} 加载完成`;
function buildIndexPromise(i, id, name) {
return {
handle: function() {
return BuildIndex(id)
},
callback: function(resp) {
let progressHint = `词典 ${name} 加载完成`;
console.log(`[app-init] building success, index: ${i}`, resp);
updater(progressHint)
}
}
}
});
let promiseArray = [];
for (let i = 0; i < res.length; i++) {
state.dictList.push(res[i]);
promiseArray.push(buildIndexPromise(i, res[i].id, res[i].name))
}
sequenceHandle(promiseArray);
// for (let i = 0; i < res.length; i++) {
// state.dictList.push(res[i]);
// console.log(`[app-init] building dictionary, index: ${i}`, res[i])
// BuildIndex(res[i].id).then((resp) => {
// let progressHint = `词典 ${res[i].name} 加载完成`;
// console.log(`[app-init] building success, index: ${i}`, resp);
// updater(progressHint)
// });
// }
});
}
Expand Down
4 changes: 4 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ require (
github.com/creasty/go-levenshtein v0.0.0-20161128082938-38ce641d5030
github.com/gin-gonic/gin v1.9.1
github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f
github.com/mattn/go-sqlite3 v1.14.17
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
github.com/rasky/go-lzo v0.0.0-20200203143853-96a758eda86e
github.com/silenceper/pool v1.0.0
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
github.com/spf13/viper v1.10.1
go.etcd.io/etcd/client/pkg/v3 v3.5.1
Expand All @@ -37,6 +39,7 @@ require (
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
github.com/konsorten/go-windows-terminal-sequences v1.0.1 // indirect
github.com/labstack/echo/v4 v4.10.2 // indirect
github.com/labstack/gommon v0.4.0 // indirect
github.com/leaanthony/go-ansi-parser v1.6.0 // indirect
Expand All @@ -57,6 +60,7 @@ require (
github.com/rivo/uniseg v0.2.0 // indirect
github.com/rogpeppe/go-internal v1.6.1 // indirect
github.com/samber/lo v1.38.1 // indirect
github.com/sirupsen/logrus v1.4.2 // indirect
github.com/spf13/afero v1.6.0 // indirect
github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
Expand Down
10 changes: 10 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f/go.mod h1:4rEELDS
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
Expand Down Expand Up @@ -84,6 +86,8 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs=
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
Expand Down Expand Up @@ -113,6 +117,10 @@ github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBO
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
github.com/silenceper/pool v1.0.0 h1:JTCaA+U6hJAA0P8nCx+JfsRCHMwLTfatsm5QXelffmU=
github.com/silenceper/pool v1.0.0/go.mod h1:3DN13bqAbq86Lmzf6iUXWEPIWFPOSYVfaoceFvilKKI=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA=
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=
Expand All @@ -126,6 +134,7 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
github.com/spf13/viper v1.10.1 h1:nuJZuYpG7gTj/XqiUwg8bA0cp1+M2mC3J4g5luUYBKk=
github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
Expand Down Expand Up @@ -178,6 +187,7 @@ golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand Down
4 changes: 0 additions & 4 deletions internal/gomdict/mdict.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,6 @@ func (mdict *Mdict) BuildIndex() error {
return err
}

err = mdict.BuildBKTree()
if err != nil {
return err
}
return nil
}

Expand Down
62 changes: 62 additions & 0 deletions internal/medengine/file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//
// Copyright (C) 2023 Quan Chen <chenquan_act@163.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

package medengine

import (
"database/sql"
_ "github.com/mattn/go-sqlite3"
"github.com/op/go-logging"
"github.com/terasum/medict/internal/utils"
)

var log = logging.MustGetLogger("default")

// CreateMeIndex creates Medict index file
// Medict words index file format:
// filename: meidx
// internal format: sqlite unzipped
// sqlite table name: meidx_keyword_index
// table columns:
// --------------------------
// | idx_no | key_word | key_block_index | record_start_offset | record_end_offset | compressed_size | decompressed_size | dict_type |
func CreateMeIndex(idxFilePath string) error {
if utils.FileExists(idxFilePath) {
return nil
}

db, err := sql.Open("sqlite3", idxFilePath)
if err != nil {
return err
}
defer db.Close()

sqlStmt := `
DROP TABLE if EXISTS meidx_keyword_index;
CREATE TABLE meidx_keyword_index (
idx_no integer primary key autoincrement not null,
key_word varchar(512) unique,
key_block_index long ,
record_start_offset long ,
record_end_offset long);
-- CREATE INDEX index_meidx_keyword_index_keyword ON meidx_keyword_index(key_word);
`
_, err = db.Exec(sqlStmt)
if err != nil {
return err
}
return nil
}
30 changes: 30 additions & 0 deletions internal/medengine/file_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// Copyright (C) 2023 Quan Chen <chenquan_act@163.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

package medengine

import (
_ "github.com/mattn/go-sqlite3"
"testing"
)

func TestCreateMeIndex(t *testing.T) {
err := CreateMeIndex("./testdata/testidx.meidx")
if err != nil {
t.Fatal(err)
}

}
1 change: 1 addition & 0 deletions internal/medengine/fulltext.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package medengine
145 changes: 145 additions & 0 deletions internal/medengine/index_engine.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package medengine

import (
"database/sql"
"github.com/silenceper/pool"
"github.com/terasum/medict/pkg/model"
"time"
)

type IndexEngine struct {
indexFilePath string
connPool pool.Pool
}

type IndexRecord struct {
keyWord string
keyBlockIndex int64
recordStartOffset int64
recordEndOffset int64
}

func NewIndexRecord(
KeyWord string,
RecordStartOffset int64,
RecordEndOffset int64,
KeyBlockIdx int64,
) *IndexRecord {
return &IndexRecord{
keyWord: KeyWord,
keyBlockIndex: KeyBlockIdx,
recordStartOffset: RecordStartOffset,
recordEndOffset: RecordEndOffset,
}
}

func (idr *IndexRecord) ToKeyBlockEntry() *model.KeyBlockEntry {
return &model.KeyBlockEntry{
ID: 0,
RecordStartOffset: idr.recordStartOffset,
RecordEndOffset: idr.recordEndOffset,
KeyWord: idr.keyWord,
KeyBlockIdx: idr.keyBlockIndex,
}
}

func NewEngine(indexFilePath string) (*IndexEngine, error) {
err := CreateMeIndex(indexFilePath)
if err != nil {
return nil, err
}

connPool, err := pool.NewChannelPool(&pool.Config{
InitialCap: 1,
MaxCap: 3,
MaxIdle: 3,
Factory: func() (interface{}, error) {
db, err1 := sql.Open("sqlite3", indexFilePath)
if err1 != nil {
return nil, err1
}
return db, nil
},
Close: func(db interface{}) error {
return db.(*sql.DB).Close()
},
Ping: func(db interface{}) error {
return nil
},
IdleTimeout: 60 * time.Second,
})
if err != nil {
return nil, err
}

return &IndexEngine{
indexFilePath: indexFilePath,
connPool: connPool,
}, nil
}

func (engine *IndexEngine) AddRecord(record *IndexRecord) error {
db, err := engine.Acquire()
if err != nil {
return err
}
defer engine.Release(db)

sqlfmt := `INSERT INTO meidx_keyword_index (
key_word,
key_block_index,
record_start_offset,
record_end_offset)
VALUES(?, ?, ?, ?)`
statement, err := db.Prepare(sqlfmt)
if err != nil {
return err
}
_, err = statement.Exec(record.keyWord, record.keyBlockIndex, record.recordStartOffset, record.recordEndOffset)
return err
}

func (engine *IndexEngine) Search(keyword string) ([]*IndexRecord, error) {
db, err := engine.Acquire()
if err != nil {
return nil, err
}
defer engine.Release(db)

sqlfmt := `SELECT key_word, key_block_index, record_start_offset, record_end_offset FROM meidx_keyword_index WHERE key_word LIKE ?`
statement, err := db.Prepare(sqlfmt)
if err != nil {
return nil, err
}
defer statement.Close()
result, err := statement.Query(keyword + "%")
if err != nil {
return nil, err
}
results := make([]*IndexRecord, 0)
for result.Next() {
temp := new(IndexRecord)
err1 := result.Scan(&(temp.keyWord), &(temp.keyBlockIndex), &(temp.recordStartOffset), &(temp.recordEndOffset))
if err1 != nil {
log.Errorf("sql query error %s", err1.Error())
}
results = append(results, temp)
}
return results, nil
}

func (engine *IndexEngine) Acquire() (*sql.DB, error) {
db, err := engine.connPool.Get()
return db.(*sql.DB), err
}

func (engine *IndexEngine) Release(db *sql.DB) {
err := engine.connPool.Put(db)
if err != nil {
log.Errorf(err.Error())
}
}

func (engine *IndexEngine) Close() {
engine.connPool.Release()
}

0 comments on commit b64c863

Please sign in to comment.