这是我参与「第三届青训营 -后端场」笔记创作活动的第5篇笔记
本文将介绍笔者团队实现搜索引擎项目基础功能所采用的技术框架和定义的接口。
一、整体框架
下图展示了搜索引擎的整体架构,按照功能将搜索引擎划分为以下三个层次。其中Web层提供与前端交互HTTP协议报文的接口,Search层实现搜索引擎的核心业务,Database数据库层提供数据持久化服务,Tokenizer分词器层提供搜索所需的分词服务。
Web层调用Search层的服务接口通过RPC协议实现,Search层则直接通过本地函数调用的方式调用Database层和Tokenizer分词器提供的服务。
暂时无法在文档外展示此内容
项目依赖的开源框架和代码库归纳如下:
| 所属层次 | 框架&代码库 | 使用目的 |
|---|---|---|
| Web | gin | HTTP引擎,解析HTTP报文 |
| kitex | 提供远程过程调用Search层搜索服务 | |
| Search | kitex | 提供远程调用服务 |
| gostl | 数据结构(堆,队列,数组)和排序算法 | |
| go-pinyin | 汉字转拼音 | |
| Database | Gorm,mysql | 数据持久化,增删改查 |
| Tokenizer | jiebago | 句子拆分为一系列关键词 |
小结
我们将此项目认定为一个认识微服务架构、RPC框架、HTTP框架的实战项目,因此在项目中使用了gin HTTP框架、kitex RPC框架和Gorm对象关系型数据库框架。
为了方便高效地实现项目中所需的算法,我们使用了gostl,go-pinyin,jiebago等开源代码库。
二、接口介绍
Database层
Database层使用mysql关系型数据库管理系统管理数据,并利用Gorm提供的面向对象的增删改查接口对数据库进行操作。Database层定义并实现了以下接口:
//初始化数据库(产生数据库全局静态变量)
func Init()
//向数据库中添加一条记录(searchapi.AddRequest的定义见下文Search层说明)
func AddIndex(ctx context.Context, req *searchapi.AddRequest, keywords []string) error
//根据关键词查询记录id
func Query(ctx context.Context, keyword string) ([]int32, bool)
//根据记录id查询记录内容
func QueryRecord(ctx context.Context, ids []int32) ([]searchapi.AddRequest, error)
//查询与记录相关的关键词
func QueryKeyWords(ctx context.Context, id int32) ([]string, bool)
注:为了使用上述的Database层提供的接口,需要在本地下载mysql并新建数据库,并将数据库的DSN注册到search/pkg/constants/constants.go文件当中
Tokenizer层
//初始化分词器(产生分词器全局静态变量)
func Init()
//将句子转为关键词
func (t *Tokenizer) Cut(text string) []string
Search层
Search层使用了thrift协议实现rpc,接口描述文件IDL如下:
namespace go SearchApi
struct AddRequest {
1: i32 id //id序号(前端要尽量保证其不重复,最好是升序)
2: string text //描述图片的相关文本
3: string url //图片的url链接
}
struct AddResponse {
1: bool status //数据库添加是否成功
}
struct QueryRequest {
1: string queryText //用户在搜索框中输入的要查询的关键词
2: string filterText //用户请求过滤的关键词
3: i32 page //用户请求的页码
4: i32 limit //每页显示的请求数目
5: i32 order //排序方式
}
struct QueryResponse {
1: double time //查询所需时间
2: i32 total //查询到的条目总数
3: i32 pagecount //查询到的页数
4: i32 page //当前页码
5: i32 limit //每页展示的数目
6: list<AddRequest> contents //查询到的内容
}
struct RelatedQueryRequest{
1: string queryText //用户在搜索框中输入的要查询的关键词
}
struct RelatedQueryResponse{
1: list<string> relatedTexts //与用户输入请求相关的文本
}
struct FindIDResponse{
1: bool found //是否找到
}
struct FindIDRequest{
1: i32 id //要查找的ID
}
service Search {
//提供支持分页、关键词过滤的查询服务
QueryResponse query(1: QueryRequest req)
//提供添加索引服务
AddResponse add(1: AddRequest req)
//提供相关搜索服务
RelatedQueryResponse relatedQuery(1: RelatedQueryRequest req)
//查询id是否存在
FindIDResponse findID(1: FindIDRequest req)
}
Web层API
web层为客户端提供了三个接口如下:
| 接口 | HTTP方法 | 路由 | 客户端调用参数 |
|---|---|---|---|
| Add | GET | /search/add | 1: i32 id //id序号2: string text //描述图片的相关文本3: string url //图片的url链接 |
| Query | POST | /search/query | 1: string queryText //用户在搜索框中输入的要查询的关键词2: string filterText //用户请求过滤的关键词3: i32 page //用户请求的页码4: i32 limit //每页显示的请求数目5: i32 order //排序方式 |
| RelatedSearch | GET | /search/relatedsearch | 1: string queryText //用户在搜索框中输入的要查询的关键词 |
客户端调用三个接口示例分别如下:
Add
响应格式:
struct AddResponse{
bool status //数据库添加是否成功
}
Query
响应格式:
struct QueryResponse {
double time //查询所需时间
int32 total //查询到的条目总数
int32 pagecount //查询到的页数
int32 page //当前页码
int32 limit //每页展示的数目
[]AddRequest contents //查询到的内容
}
RelatedSearch
响应格式:
struct RelatedQueryResponse{
string[] relatedTexts //与用户输入请求相关的文本
}
小结
此小节按照自底向上的顺序对项目各层次的接口进行了介绍,展示了项目实现的基础功能以及每个功能背后的调用关系。