ElasticSearch7 实现全文检索、关键词高亮

1. 全文检索概念;

相关概念
全文检索就是对全文数据的检索
数据分类:结构化数据、非结构化数据
结构化数据
行数据,储存在数据库里,可以用 二维表结构来逻辑表达实现的数据
能够用数据或统一的结构加以表示
在数据表中,可以用 数字和符号进行表示的数据
比如在数据表中存储一个商品的库存,可以用一个整型进行存储,存储的是一个数字
存储一个商品的价格,可以用一个浮点进行存储
给用户存储性别,可以用枚举来进行存储
以上举例都称之为结构化数据
非结构化数据
无法用数字或者统一的结构表示
文本、图像、声音、网页都可称之为非结构化数据,在我们数据表里体现方式是文本, 文本就是非结构化数据
结构化数据属于非结构化数据
非结构化数据就是 全文数据;对全文数据的检索,就是全文检索
全文检索
概念:一种将文件中或者数据库中所有文本与检索项匹配的文字资料检索的方法
对全文数据的检索,就是全文检索
顺序扫描法:会将数据表中所有的记录挨个进行扫描,然后再对每一条记录里的内容逐次扫描,把要搜索的内容显示出来。这种方式扫描起来非常慢,效率非常低下。
索引扫描法:全文检索的基本思路,也就是将非结构化数据中的一部分信息提取出来,重新组织,使其变得有一定结构,然后对此有一定结构的数据进行搜索,从而达到搜索相对较快的目的。
对结构化数据检索的时候是非常快的,索引扫描法就是运用了这样一个思路,先把非结构化的数据变得结构化,将里面的文本全部都拆开,打成一个一个的词元,然后挨个的创建索引。
全文检索过程
创建索引、搜索索引
创建索引
索引保存了什么?索引就是一个字典(如下图一)
如何创建索引
第一步:一些要索引的原文档(Document,下图二)
第二步:将原文档传给分词组件(Tokenizer)。将文档分成一个一个单独的单词、去除标点符号、去除停词(Stop word:a,the 类似这种没有意义的词),得到词元。(下图三)
第三步:将得到的词元(Token)传递给语言处理组件(Linguistic Processor)。
‐ 会将单词变为小写(Lowercase)
‐ 将单词缩减为词根形式,如 “cars” 到 “car”
‐ 将单词转换为词根,如 “drove” 到 “drive”
第四步:将得到的词(Term)传给索引组件(Indexer)
‐ 利用得到的单词(Term)创建一个字典
‐ 对字典进行按字母顺序排序
‐ 合并相同的词(Term)成为文档倒排(Posting List)链表(见图四、五)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如何搜索索引
第一步:用户输入查询语句(交给词法分析组件、语法分析组件)
第二步:对查询语句进行词法分析、语法分析、及语言处理,打成词元
第三步:根据词元搜索索引,得到符合的文档 id,根据文档 id 得到结果
搜索索引和前面的步骤一样,只不过没有创建索引

2. 全文检索引擎 ElasticSearch;

相关概念
全文检索引擎是目前广泛应用的主流搜索引擎。
它的工作原理是计算机索引程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。
使用这种检索方式的软件或者产品称之为全文搜索引擎。
相关产品
Lucene、Sphinx、Xapian、Nutch、DataparkSearch、 ElasticSearch
ElasticSearch 介绍
是一个基于 Apache Lucene(TM)的开源搜索引擎。无论在开源还是专有领域,Lucene 可以被认为 是迄今为止最先进、性能最好、功能最全的搜索引擎库。
ElasticSearch 也使用 Java 开发并使用 Lucene 作为其核心来实现所有索引和搜索功能,但是它的目的是通过简单的 RESTful API 来隐藏 Lucene 的复杂性,从而让全文搜索变得简单
分布式的实时文件存储,每个字段都被索引并且可被搜索
分布式的实时分析搜索引擎
可以扩展到上百台服务器,处理 PB 级结构化或非结构化数据
所有功能集成在一个服务里面,可以通过 RESTful API、各种语言的客户端甚至命令行与之交互
上手容易,提供了很多合理的缺省值,开箱即用,学习成本低
可免费下载、使用和修改
配置灵活
官网地址: https://www.elastic.co/cn/

3. 安装 ElasticSearch 以及中文分词插件 IK;

3.1 安装 ElasticSearch7;

  • 安装
# 下载最新 es 7.5
cd /usr/local/src
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.5.0-linux-x86_64.tar.gz

# 解压到指定安装目录
tar zxvf elasticsearch-7.5.0-linux-x86_64.tar.gz -C /usr/local/elasticsearch
  • 修改配置文件
vim /usr/local/elasticsearch/config/elasticsearch.yml

# 1. 配置集群名称
#cluster.name: my-application
# 修改为
cluster.name: el-search

# 2. 配置节点名称
#node.name: node-1
# 修改为
node.name: master-1

# 关于 path.data (数据存储路径)
# 在进行数据的存储的时候,比如说向 MySQL 插入一条数据,
# 比如要插入一个商品,商品有标题,有描述,
# 为了让用户通过一个关键字搜索标题或者描述,首先要将这样的数据插入到 ES 里
# 然后通过 ES 建立索引,再找到对应的文档。所以需要保存一些数据
# 向 MySQL 插入一条数据,意味着也要向 ES 里插入一条数据,当然数据不用放全部,只要放标题和描述就行

# 3. 配置 Network
# 访问 ES 的内容通过 RESTful API 进行访问
# 所以需要提供 HTTP 主机地址,保证本机和其它机器通过浏览器都能访问
#network.host: 192.168.0.1
# 修改为
network.host: 0.0.0.0
# 端口默认 9200
http.port: 9200

# 4. Discovery
# 如果启动 ES 时报错信息为
# “the default discovery settings are unsuitable for production use; 
# at least one of [discovery.seed_hosts, discovery.seed_providers, cluster.initial_master_nodes] 
# must be configured
# 则需要修改以下配置
# cluster.initial_master_nodes: ["node-1", "node-2"]
# 修改为
cluster.initial_master_nodes: ["master-1"]
  • 启动 ES
# 指令后加 “-d” 为后台启动
/usr/local/elasticsearch/bin/elasticsearch -d

# 检查是否启动成功
curl localhost:9200

# 检查浏览器里是否可以访问
# 打开客户端浏览器输入,有 json 信息返回,启动成功
http://192.168.2.214:9200

# 报错:can not run elasticsearch as root
# elasticsearch 禁止 root 账号启动
# 解决方案:
useradd es	# 设置空密码
chown -R es /usr/local/elasticsearch/
su es
bin/elasticsearch -d

# 修改系统配置的 max_map_count 项
sysctl -w vm.max_map_count=262144

vim /etc/sysctl.conf
# 末尾添加
vm.max_map_count = 655360

# 修改
vim /etc/security/limits.conf

# 末尾添加
*** hard nofile 65536
*** soft nofile 65536

# 开机自启动配置:
vim /etc/systemd/system/elasticsearch.service
# 写入如下内容
[Unit]
Description=elasticsearch
[Service]
User=es
LimitNOFILE=100000
LimitNPROC=100000
ExecStart=/usr/local/elasticsearch/bin/elasticsearch
[Install]
WantedBy=multi-user.target
# 写入内容结束

# 保存退出
systemctl enable elasticsearch

3.2 安装 elasticsearch-head;

# 参考:https://github.com/mobz/elasticsearch-head
# 安装完成后,配置文件 elasticsearch.yml 添加以下代码
http.cors.enabled: true
http.cors.allow-origin: "*"

# 启动
npm run start

3.3 ElasticSearch 设置密码;

# 修改配置文件
vim /usr/local/elasticsearch/config/elasticsearch.yml
# 添加以下内容
# http.cors.enabled: true
# http.cors.allow-origin: "*"
http.cors.allow-headers: Authorization,X-Requested-With,Content-Length,Content-Type
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true

# 切换 es 用户重启 ElasticSearch 后
/usr/local/elasticsearch/bin/elasticsearch-setup-passwords interactive
# 按提示设置密码

# 登录 Elasticsearch-head
# http://localhost:9100/?auth_user=elastic&auth_password=xxxxxx
# 注意,之后在 Kibana 配置文件中设置好 ES 的用户名和密码后
# 登录 Kibana 也是这套用户名和密码

3.4 安装中文分词插件 IK;

# ES 的全文检索本身对中文并不是特别友好
# 也就是说,给它一大段的中文,它分词的时候,分的并不是特别的智能
# 它会把一大段中文分成一个一个的汉字,搜索的时候智能化不是特别的强,搜一个词不太好搜
# 所以需要安装插件:https://github.com/Medcl/elasticsearch-analysis-ik

# 下载插件
cd /usr/local/src
wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.5.0/elasticsearch-analysis-ik-7.5.0.zip

# 在 elasticsearch 的 plugins 新建目录 ik
mkdir /usr/share/elasticsearch/plugins/ik


# 插件压缩包解压到 ik 目录
unzip elasticsearch-analysis-ik-7.5.0.zip -d /usr/share/elasticsearch/plugins/ik

# 重启

4. 创建索引;

# 参考文档:https://www.elastic.co/guide/en/elasticsearch/reference/7.5/indices-create-index.html
# 1. 创建 json 文件:createindex.json,写入如下内容
{
	"settings": {
		"refresh_interval": "5s",
		"number_of_shards": 1,
		"number_of_replicas": 0
	},
	"mappings": {
		"properties": {
			"productid": {"type": "long"},
			"title": {"type": "text", "index": true, "analyzer": "ik_smart"},
			"descr": {"type": "text", "index": true, "analyzer": "ik_smart"},
			"type": {"type": "text"}
		}
	}
}

# 注释:
# "refresh_interval": "5s",	// 每 5s 索引刷新一次(默认 1s,对服务压力大)
# "number_of_shards": 1,	// 索引分片,没有做分布式就设置 1
# "number_of_replicas": 0,	// 副本的数量
# "analyzer": "ik_smart",	// 分词器

# type 类型为 text:1. 会分词,然后进行索引,用于全文搜索 2. 支持模糊、精确查询 3. 不支持聚合
# type 类型为 keyword:1. 不进行分词,直接索引,用于关键词搜索 2. 支持模糊、精确查询 3. 支持聚合

# 2. 创建索引
curl -H 'Content-Type: application/json' \
-XPUT "http://192.168.2.214:9200/shop/_doc/1?pretty" -d'@createindex.json'
# 返回:
{
  "_index" : "shop",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}

# 3. 查询索引
curl -XGET "http://192.168.2.214:9200/_cat/indices?v"

5. 全文数据检索以及关键字高亮显示;

# 参考文档:https://www.elastic.co/guide/en/elasticsearch/reference/7.5/docs-index_.html
# 1. 为索引添加数据:
curl -H 'Content-Type: application/json' \
-XPUT "http://192.168.2.214:9200/shop/_doc/1?pretty" \
-d '{"productid":1, "title":"这是一个商品的标题", "descr":"这是一个商品的描述", "type":"products"}'
# 返回
{
  "_index" : "shop",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 1,
  "result" : "updated",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 1,
  "_primary_term" : 1
}

# 再添加一条数据
curl -H 'Content-Type: application/json' \
-XPUT "http://192.168.2.214:9200/shop/_doc/2?pretty" \
-d '{"productid":2, "title":"这是一个手机", "descr":"这是一个手机的描述", "type":"products"}'

# 2.1 查找索引数据:
# 参考文档: https://www.elastic.co/guide/en/elasticsearch/reference/7.5/search.html
curl -XGET "http://192.168.2.214:9200/shop/_search?pretty"
# 返回
{
  "took" : 1,			# 查询花费的毫秒数
  "timed_out" : false,	# 是否超时
  "_shards" : {			# 分片信息
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {			# 命中的信息
    "total" : {
      "value" : 2,		# 命中 2 条
      "relation" : "eq"
    },
    "max_score" : 1.0,	# 最大分值:进行全文搜索的时候,搜索词的相关性打分
    "hits" : [
      {
        "_index" : "shop",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "productid" : 1,
          "title" : "这是一个商品的标题",
          "descr" : "这是一个商品的描述",
          "type":"products"
        }
      },
      {
        "_index" : "shop",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : {
          "productid" : 2,
          "title" : "这是一个手机",
          "descr" : "这是一个手机的描述",
          "type":"products"
        }
      }
    ]
  }
}

# 2.2 搜索关键词
# 创建 json 文件:search.json,写入如下内容
# 如果搜索一个字段:match->match->字段
# 高亮模式:https://github.com/Medcl/elasticsearch-analysis-ik,搜索“highlight”
{
	"query": {
		"multi_match":{
			"query": "手机",
			"fields": ["title", "descr"]
		}
	},
	"highlight" : {
        "pre_tags" : ["<i class=\"highlight\">"],
        "post_tags" : ["</i>"],
        "fields" : {
            "title" : {},
            "descr" : {}
        }
    }
}
curl -H 'Content-Type: application/json' \
-XPOST "http://192.168.2.214:9200/shop/_search?pretty" -d'@search.json'
# 返回
{
  "took" : 7,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.5098255,
    "hits" : [
      {
        "_index" : "shop",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.5098255,
        "_source" : {
          "productid" : 2,
          "title" : "这是一个手机",
          "descr" : "这是一个手机的描述",
          "type":"products"
        },
        "highlight" : {
          "descr" : [
            "这是一个<i class=\"highlight\">手</i><i class=\"highlight\">机</i>的描述"
          ],
          "title" : [
            "这是一个<i class=\"highlight\">手</i><i class=\"highlight\">机</i>"
          ]
        }
      }
    ]
  }
}
发布了119 篇原创文章 · 获赞 12 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/hualaoshuan/article/details/102306850