solr学习笔记

191 阅读8分钟

lucene

全文检索

将非结构化数据中的一部分信息提取出来,重新组织,使其变得有一定结构,然后对此有一定结构的数据进行搜索,从而达到搜索相对较快的目的。这部分从非结构化数据中提取出的然后重新组织的信息,我们称之索引

以字典为例:

字典的拼音表和部首检字表就相当于字典的索引,对每一个字的解释是非结构化的,如果字典没有音节表和部首检字表,在茫茫辞海中找一个字只能顺序扫描。然而字的某些信息可以提取出来进行结构化处理,比如读音和偏旁部首,它就比较结构化,于是将读音和偏旁部首拿出来按一定的顺序排列,每一项都指向此字的详细解释的页数。我们搜索时按结构化的拼音搜到读音,然后按其指向的页数,便可找到我们的非结构化数据(也即对字的解释)。

这种先建立索引,再对索引进行搜索的过程就叫全文检索(Full-text Search) 。虽然创建索引的过程是非常耗时的(类比字典制作出来那可是相当费时的),但是索引一旦创建就可以多次使用,全文检索主要处理的是查询,所以耗时间创建索引是值得的。

怎么实现全文检索呢?

我们可以使用Lucene来实现全文检索。Lucene是apache下的一个开放源代码的全文检索引擎工具包(它提供了许多的jar包,即实现全文检索的类库)。它提供了完整的查询引擎和索引引擎,部分文本分析引擎。Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便地在目标系统中实现全文检索的功能。

索引创建和查询流程

lucene的全文检索过程分为(创建)索引、(索引)搜索两个过程。 具体流程可以看下图:

image.png

以一个案例来说明: 现在有这样一个需求:实现一个文件的搜索功能,通过关键字搜索文件,凡是文件名或文件内容包括关键字的文件都需要找出来,除此之外,还可以根据中文词语进行查询,并且需要支持多个条件查询。假设本案例中的原始内容就是磁盘上的文件,如下图所示。

image.png

  • 获取文档

从互联网上、数据库、文件系统中等数据源处获取需要搜索的原始信息。

  • 构建文档对象

获取原始内容的目的是为了索引,在索引前需要将原始内容创建成文档(Document),文档中包括一个一个的域(Field),域中存储内容。文档类似数据库中的一条数据,域类似数据库中的字段。

因为我们需要找磁盘中的某个文件,所以可以将磁盘上的一个文件当作成一个Document,Document中包括一些Field,例如file_name(文件名称)、file_path(文件路径)、file_size(文件大小)、file_content(文件内容)等,如下图所示。

image.png

注意:每个Document可以有多个Field,不同的Document可以有不同的Field,同一个Document可以有相同的Field(域名和域值都相同)。而且,每个文档都有一个唯一的编号,就是文档id。

分析文档

将原始内容创建为包含域(Field)的文档(Document),需要再对域中的内容进行分析,分析的过程是经过对原始文档提取单词、将字母转为小写、去除标点符号、去除停用词(没有意义的单词) 等过程生成最终的语汇单元,我们可以将语汇单元理解为一个一个的单词。例如,假设原始文档内容如下:

我们可以使用Lucene来实现全文检索,Lucene是apache下的一个开放源代码的全文检索引擎工具包。

上边的文档经过分析得出的语汇单元为:

lucene、全文检索、apache、引擎、工具包…

每个单词叫做一个Term,不同的域中拆分出来的相同的单词是不同的Term(同一个域中拆分出来的相同的单词是同一个Term),例如,文件名中包含的apache和文件内容中包含的apache是不同的Term。Term中包含两部分内容,一部分是文档的域名,另一部分是单词的内容。Term有点类似于Map<K, V>,你可以将文档的域名看作是Term中的键,单词的内容看作是Term中的值。<file_name: apache, file_content: apache...>,关键词搜索其实就是对语汇单元term进行搜索。

  • 创建索引

将文档分析得到的语汇单元和文档本身的内容存储到索引库,所以索引库实际上包含了索引和文档内容两部分。

创建索引是为了对语汇单元进行查询,通过词语找文档,这种索引的结构叫倒排索引结构。传统方法是根据文件找到该文件的内容,在文件内容中匹配搜索关键字,这种方法是顺序扫描方法,数据量大、搜索慢。

倒排索引结构是根据内容(词语)找文档,如下图所示。
这里写图片描述

索引创建和搜索的整个流程如下图: image.png

solr

Solr是Apache下的一个顶级开源项目,采用Java开发,它是基于Lucene的全文搜索服务器。Solr提供了比Lucene更为丰富的查询语言,同时实现了可配置、可扩展,并对索引、搜索性能进行了优化。

与lucene的区别

lucene是一个开源的用于实现全文检索的工具包,不能独立运行。solr是基于lucene开发的全文检索的服务,作为一个搜索的服务独立运行。

solr是一个分布式的搜索引擎,但是这里介绍的是单机版的solr的架构图

image.png

solr的安装

docker安装

简单点就用docker-compose来安装

version: '3.9'
services:
  solr:
    image: solr:8.11.1
    container_name: solr
    ports:
      - '8983:8983'
    restart: always
    privileged: true
    volumes:
      - '/home/ubuntu/solr/data:/var/solr/data/'
      - '/home/ubuntu/solr/server/solr-8.11.1:/opt/solr-8.11.1'

注意一下数据卷的挂载:

1.先不挂载数据卷启动,进入容器找到solr的data和solr服务的路径。

2.在本地创建一个solr文件夹,在solr下创建data和server用来挂载solr的data和服务。

启动后访问:http://81.70.245.149:8983/ 可以进入solr的管理后台

image.png

创建core

docker exec -it solr bin/solr create_core -c ik_core

core可以类比pg的数据库来理解。

分词器配置

使用的是IK分词器:github.com/magese/ik-a…

下载jar

search.maven.org/search?q=co…

将jar包放入 solr 服务的 Jetty 或 Tomcat 的 webapp/WEB-INF/lib/ 目录下

docker cp ik-analyzer-8.5.0.jar solr:/opt/solr-8.11.1/server/solr-webapp/webapp/WEB-INF/lib/
shell

复制配置文件

# 使用root用户(超级管理)进入 solr 的容器里创建文件夹
docker exec  -it --user=root solr /bin/bash

# 创建文件夹(classes)
cd /opt/solr-8.4.0/server/solr-webapp/webapp/WEB-INF
mkdir classes

# 退出容器
exit

# 将下面的5个配置文件放入solr服务的Jetty或Tomcat的webapp/WEB-INF/classes/目录下
① IKAnalyzer.cfg.xml
② ext.dic
③ stopword.dic
④ ik.conf
⑤ dynamicdic.txt

docker cp IKAnalyzer.cfg.xml solr:/opt/solr-8.4.0/server/solr-webapp/webapp/WEB-INF/classes/
...

配置 solr 的 managed-schema,添加ik分词器

docker exec -it  --user=root solr /bin/bash
cd /var/solr/data/ik_core/conf
vi managed-schema

添加如下:

<!-- ik分词器 -->
<fieldType name="text_ik" class="solr.TextField">
  <analyzer type="index">
      <tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory" useSmart="false" conf="ik.conf"/>
      <filter class="solr.LowerCaseFilterFactory"/>
  </analyzer>
  <analyzer type="query">
      <tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory" useSmart="true" conf="ik.conf"/>
      <filter class="solr.LowerCaseFilterFactory"/>
  </analyzer>
</fieldType>

重启 solr 查看分词效果

docker restart solr

image.png

ruby中使用solr

rsolr

rsolr 是一个 Ruby 的库,它提供了与 Solr 搜索引擎的交互能力。封装了很多操作方法使得ruby开发者能够轻松地与 Solr 实例进行交互,包括索引文档、查询以及管理索引。

require 'rsolr'

# 创建一个 Solr 实例
solr = RSolr::Client.new("http://localhost:8983/solr")

# 创建一个文档
doc = RSolr::Document.new
doc.add_field("id", "12345")
doc.add_field("title", "The Great Gatsby")
doc.add_field("author", "F. Scott Fitzgerald")
# 索引文档
solr.add(doc)

# 查询
params = RSolr::Params.new
params.add("q", "Gatsby")
params.add("fl", "id,title")
# 执行查询
response = solr.get(params)
puts response.status
puts response.body

# 删除文档
solr.delete_by_id("12345")

# 更新文档
doc = RSolr::Document.new
doc.add_field("id", "12345")
doc.add_field("title", "The Great Gatsby")
doc.add_field("author", "F. Scott Fitzgerald")
# 更新文档
solr.update(doc)

sunspot

Sunspot 用 Ruby 的方式实现了与 Solr 搜索引擎的交互。底层是基于 Rsolr,而且提供了很方便的 DSL 接口实现建立索引和搜索。 sunspot的基本用法:

1、 在 Gemfile 中添加gem,bundle安装

gem "sunspot_rails", "~> 2.5"
gem "sunspot_solr", "~> 2.5" # 开发环境使用,本地的solr环境

2、 接着生成配置文件config/sunspot.yml:

rails generate sunspot_rails:install

3、配置config/sunspot.yml

production:
  solr:
    hostname: localhost
    port: 8983
    log_level: WARNING
    path: /solr/production
    # read_timeout: 2
    # open_timeout: 0.5

development:
  solr:
    hostname: localhost
    port: 8983
    log_level: INFO
    path: /solr/ik_core # solr的core的名称

test:
  solr:
    hostname: localhost
    port: 8983
    log_level: WARNING
    path: /solr/ik_core

4、对象的设置

class Article < ActiveRecord::Base
    searchable do
        text :title
        text :slug
        integer :view_counts
    end
end

5、对象搜索

# fulltext会在所有的text类型字段中搜索
Article.search do
    fulltext '教程'
    with(:view_count).more_than 100
end.results

常用的语法:

  1. fulltext: 用于执行全文搜索。可以指定要搜索的关键词或短语。
Model.search do
  fulltext 'keyword'
end
  1. keywords: 用于执行关键词搜索,类似于fulltext,但更适合处理多个关键词。
Model.search do
  keywords 'keyword1 keyword2'
end
  1. with: 用于添加过滤条件,限定搜索结果。
Model.search do
  with(:field_name).equal_to(value)
end
  1. any_of: 用于指定多个条件之间的逻辑关系,表示其中任意一个条件满足即可。all_of表示满足所有条件。
Model.search do
  any_of do
    with(:field_name1).equal_to(value1)
    with(:field_name2).equal_to(value2)
  end
end
  1. order_by: 用于指定搜索结果的排序方式。
Model.search do
  order_by(:field_name, :asc)
end
  1. paginate: 用于分页查询结果。
Model.search do
  paginate(:page => 1, :per_page => 10)
end

参考资料: explorexd.com/articles/34 github.com/sunspot/sun… www.w3cschool.cn/solr_doc/