# 搜索引擎Typesense的使用

By [Yooma](https://paragraph.com/@yooma) · 2022-09-01

---

注： 使用语言 python

一：Typesense介绍
-------------

[**Typesense**](https://typesense.org/)**将数据保存在磁盘当中，建立的索引保存内存中**

[**Typesense**](https://typesense.org/)**是一个开源的、有容错能力的搜索引擎，针对实时（通常低于 50 毫秒）搜索即键入体验和开发人员生产力进行了优化。**

[**Typesense**](https://typesense.org/)**做了一个对于其他搜索引擎的对比。（**[**文档版**](https://typesense.org/docs/overview/comparison-with-alternatives.html#typesense-vs-elasticsearch)**，**[**表格版**](https://typesense.org/typesense-vs-algolia-vs-elasticsearch-vs-meilisearch/)**）**

**索引数据速度以及资源占用：**

对于220万份食谱（一份食谱相当于下文中提到的一个document）

*   在 Typesense 中进行索引时占用了大约 900MB 的 RAM(内存)
    
*   花了 3.6 分钟索引所有 220 万条记录
    
*   在具有 4 个 vCPU 的服务器上，Typesense 每秒能够处理**104 个并发搜索查询**，平均搜索处理时间为11**毫秒**。
    

RAM(内存)方面：如果数据量为 X MB大小，则需要占用2X-3XRAM（2-3倍数据量大小的占用）

如需深入了解可以查阅[官方文档](https://typesense.org/docs/overview/what-is-typesense.html)

二：Typesense的用法
--------------

### 1：使用typesense有两种方法

*   使用自带的[云服务](https://cloud.typesense.org/?_ga=2.203234129.1158743537.1661761009-664941336.1661147797)，配置运行简单（收费）
    
*   在本地安装[typesense](https://typesense.org/docs/guide/install-typesense.html#option-2-local-machine-self-hosting)，自己维护配置（本文使用这种方法）
    

### 2：安装启动typesense

### （1）：下载并安装

centos:（如果您的系统不是centos可以在[官方文档](https://typesense.org/docs/guide/install-typesense.html#%F0%9F%93%A5-download-install)中找到对应的下载方法

    curl -O https://dl.typesense.org/releases/0.23.1/typesense-server-0.23.1-1.x86_64.rpm
    sudo yum install ./typesense-server-0.23.1-1.x86_64.rpm
    

### （2）：启动服务查看状态

如果从rpm包中安装typesense会自动启动服务，使用下面命令查看服务状态

    sudo systemctl status typesense-server.service
    

Active 是 running 则代表已启动

*   配置文件位于`/etc/typesense/typesense-server.ini`
    
*   日志在`/var/log/typesense/`
    
*   数据目录在`/var/lib/typesense/`
    

日志目录和数据目录可以在配置文件中更改

### （3）：服务启动后检查是否可以接收到请求

    curl http://localhost:8108/health
    {"ok":true}
    

### （4）：安装client

这是python版本的，如果需要其他版本可以在[官网](https://typesense.org/docs/guide/installing-a-client.html)上查看

3：构建数据集用于检索
-----------

### （1）：下载一份测试数据

数据来源[typesense官网](https://typesense.org/docs/guide/building-a-search-application.html#sample-dataset) 用于测试，如果自己有测试数据直接使用即可

    cd /typesense_test    # 任意目录 
    curl -O https://dl.typesense.org/datasets/books.jsonl.gz
    gunzip books.jsonl.gz
    

### （2）：初始化client

    import typesense
    
    client = typesense.Client({
      'nodes': [{
        'host': 'localhost', # For Typesense Cloud use xxx.a1.typesense.net
        'port': '8108',      # For Typesense Cloud use 443
        'protocol': 'http'   # For Typesense Cloud use https
      }],
      'api_key': '<API_KEY>',    # api-key 在 一-->2-->（2）中提到的配置文件中可以查看
      'connection_timeout_seconds': 2  
    })
    

这样就可以和typesense交互了

**以下代码都是在建立交互的基础上运行**

### （3）：创建存放书籍数据的collection

**在 typesense 中，一个 collection 相当于关系型数据库中的一张表**

**而 Documents 相当于表中的每条数据**

**创建一个 collection 时需要指定一些字段名和类型**

（继续初始化代码，在初始化后：）

（如果使用自己数据需要根据数据的值类型来设置collection fields中的name type等）

    books_schema = {
      'name': 'books',    # collection 的名字，对该集合操作都是根据该名字
      'fields': [
        {'name': 'title', 'type': 'string' },
        {'name': 'authors', 'type': 'string[]', 'facet': True },  ###'facet': True facet字段被逐字索引
        {'name': 'publication_year', 'type': 'int32', 'facet': True },
        {'name': 'ratings_count', 'type': 'int32' },
        {'name': 'average_rating', 'type': 'float' }
      ],
      'default_sorting_field': 'ratings_count'  # 在没有sort_by时检索结果默认以ratings_count字段排序
    }
    
    client.collections.create(books_schema)
    
    ######## 字段类型
    type	描述
    string	字符串值
    string[]	字符串数组
    int32	整数值高达 2,147,483,647
    int32[]	数组int32
    int64	大于 2,147,483,647 的整数值
    int64[]	数组int64
    float	浮点数/十进制数
    float[]	浮点数/十进制数数组
    bool	true或者false
    bool[]	布尔数组
    geopoint	纬度和经度指定为[lat, lng]
    geopoint[]	纬度和经度数组指定为[[lat1, lng1], [lat2, lng2]]
    string*	string自动将值转换为 a或的特殊类型string[]。   ###如果传入的值为1，那么会自动转化成 ‘1’
    auto	自动尝试根据添加到集合中的文档推断数据类型的特殊类型。请参阅自动模式检测。
    

### （4）：添加数据

**在创建完成后需要向里面添加数据，将刚刚下载好的测试数据添加到collection中**

    with open('/typesense_test/books.jsonl') as jsonl_file:
      client.collections['books'].documents.import_(jsonl_file.read().encode('utf-8'))    # books--collection中定义的name
    

**或者自己有数据需要向里面添加**

    ## 导入单条数据
    document = {
      'id': '124',    ### 可以指定，也可以不指定，不指定的情况下就按自增的来
      'company_name': 'Stark Industries',    ### 以下字段是需要包含在collection中的字段，就相当于往数据表中添加数据，指定每个字段的值，如果collection中的有a字段在document中没有指定a字段的值，那么该条document在collection中没有a字段，在以后更新的时候可以再写入
      'num_employees': 5215,
      'country': 'USA'
    }
    
    client.collections['collection_name'].documents.create(document)
    
    ## 导入多条数据 数据集 在数据量比较大的情况下 这个方法效率很高
    documents = [{
      'id': '124',
      'company_name': 'Stark Industries',
      'num_employees': 5215,
      'country': 'USA'
    }]
    
    # IMPORTANT: Be sure to increase connection_timeout_seconds to at least 5 minutes or more for imports,
    #  when instantiating the client
    
    client.collections['collection'].documents.import_(documents, {'action': 'create'})
    action
     create  创建一个新的document，如果collection中有了相同的id，则创建失败
     update  更新一个document，如果没有指定id，则更新失败
     upsert  创建一个新document，或者在有该id的情况下更新该id的数据，需要发送整个document
     emplace 创建一个新document，或者在有该id的情况下更新该id的数据，可以发送部分document或整个document
    

### （5）： 搜索数据

**单个collection搜索**

     
    search_parameters = {
      'q'         : 'harry potter',  # 搜索词
      'query_by'  : 'title',          # 从title字段中检索
      'sort_by'   : 'ratings_count:desc'  # 将搜索结果按ratings_count倒排
    }
    
    client.collections['books'].documents.search(search_parameters)
    

**多个collection一起搜索**

    search_requests = {
      'searches': [
        {
          'collection': 'books',
          'query_by': 'title, authors'  #
        },
        {
          'collection': 'collection_name1',  
          'query_by': 'field1, field2, field3'
        },
        {
          'collection': 'collection_name2',
          'query_by': 'field1'
        }
      ]
    }
    
    common_search_params = {
        'q': 'xxxx'    # 搜索词   相同的内容可以放在这里面，代表从每个collection中检索该词  如果query_by 都相同的情况下也可放在这里，把上面的去掉
    }
    
    client.multi_search.perform(search_requests, common_search_params)
    

**对于搜索结果的处理以及排序方式还有疑问可以查阅**[**官方文档**](https://typesense.org/docs/0.23.1/api/search.html#group-results)

### （6）：查看 collection 和 document

**查看collection，返回collction结构（例如数据表的结构）**

    # 单个collection
    client.collections['collection_name'].retrieve()
    
    # 所有collection
    client.collections.retrieve()
    

**查看 document 数据**

    # 查看document
    client.collections['collection_name'].documents['124'].retrieve() # 查看该collection中id为124的document的数据
    

### （7）：更改 collection 和 document

**更改collection结构**

    update_schema = {
      'fields': [    
        {
          'name'  :  'num_employees',
          'drop'  :  True    ## 删除该字段
        },
        {
          'name'  :  'company_category',
          'type'  :  'string'
        }
      ]
    }
    client.collections['collection_name'].update(update_schema)
    

**更新document数据**

    document = {
      'company_name': 'Stark Industries',
      'num_employees': 5500
    }
    
    client.collections['collection_name'].documents['124'].update(document)  ## 更新documentid为124的数据
    

### （8）：删除 collection 和 document

**删除 collection**

    client.collections['collection_name'].delete()
    

**删除 document**

    client.collections['collection_name'].documents['124'].delete()  # 删除 id为124的document
    

注：[官方文档api](https://typesense.org/docs/0.23.1/api/collections.html)

---

*Originally published on [Yooma](https://paragraph.com/@yooma/typesense)*
