为了账号安全,请及时绑定邮箱和手机立即绑定

Elasticsearch全文检索入门这一篇就够了

标签:
机器学习

本文仅针对搜索与Elasticsearch小白,先介绍了全文搜索的原理,然后介绍了Elasticsearch中的一些基本概念,接着讲解如何在Elasticsearch中插入文档构建查询索引,最后介绍Elasticsearch的线上查询API的使用方式。

全文搜索原理

顺序扫描

如何实现全文搜索?最简单的方法就是用正则去匹配文档中的字符串。这种方式看似粗暴,但却不乏使用场景,比如Linux中的grep命令,Windows中用Ctrl+F在文件中进行查找等。

这种方式的缺点就是效率低,需要扫描全部文件,有时候搜索一个磁盘可能检索大半个小时。但Mac的spotlight搜索却是非常快,这是如何实现的了?

倒排索引

大家都知道,在数据库中直接全表查询的时间复杂度是o(n),如果对索引列进行查询,其时间复杂度为o(logn),如果数据以key-value形式存储,查询时间复杂度将降为o(1)。那么在全文搜索中我们直接建立从查询词到文档的映射是不是也就获得了o(1)的查询性能?这种词汇到文档的映射被称之为倒排索引。那么倒排索引是如何构建的呢?一般流程如下:

加入你有3篇文档

\begin{array}[b]{|c|c|}  \hline ID & Content\  \hline 1 & 秋水浮萍 \  \hline 2 & 秋水任飘渺 \  \hline 3 & 一叶浮萍任飘渺 \  \hline  \end{array}

经过切词后得到每篇文档的词袋表示,即每篇文档所包含的词

\begin{array}[b]{|c|c|}  \hline ID & Content\  \hline 1 & 秋水, 浮萍 \  \hline 2 & 秋水,任飘渺 \  \hline 3 & 一叶,浮萍,任飘渺 \  \hline  \end{array}

然后再构建从词汇到文档ID的映射

\begin{array}[b]{|c|c|}  \hline ID & Content\  \hline 秋水 & 1,2 \  \hline 浮萍 & 1,3 \  \hline 任缥缈 & 2,3 \  \hline 一叶 & 3 \  \hline  \end{array}

当然实际在切词后还会做一些去停用词、词目还原等操作,以提升索引质量。

下面将介绍如何用Elasticsearch完成上面倒排索引的构建过程,然后在倒排索引上进行各种查询。

基本概念

索引、类型与文档

索引:含相同属性的文档集合。相当于关系型数据库中的一个database

类型:索引可以定义一个或者多个类型,文档必须属于一个类型,其相当于关系型数据库中的表,是通过mapping定义的。mapping中主要包括字段名、字段数据类型和字段索引类型这3个方面的定义,相当于关系型数据库中的schema。

文档:可以被索引的基本数据单位,也是全文搜索中被搜索的对象,可以对应一个网页,一篇txt文档或者一个商品。 相当于关系型数据库中的表中的一行记录。

举个例子,假设现在有大量的数据,有网页,有图片,有视频,有学术论文等,现在你打算基于这些数据用ES打造一个搜索引擎。由于这些数据高度异构,你可能对网页、图片、视频、论文等分别构建不同的”索引“。以Bing搜索为例,其上方的不同选项卡,对应着不同的索引。

在学术论文索引中,为了支持作者查询,机构查询,发表时间查询等多种查询模式,你需要定义多种”类型“,在定义”类型“时,你需要通过mapping文件定义各个字段的类型,处理方式(如切词、过滤等),然后所有文档将基于这个mapping文件来构建倒排索引。可以说一个”类型”对应一个倒排索引表。

具体的一篇论文即为一篇”文档“。

分片 备份

分片

有时候一个索引的数据量非常大,甚至超出了单机的存储能力,这个时候需要对索引分片存储,分别存到不同机器上。

备份

为了防止节点故障到时索引分片丢失,一般会对分片进行备份。备份除了可以保障数据安全性,还可以分担搜索的压力。

ES创建索引默认5个分片,1个备份,分片只能在创建索引的时候指定而备份可以后期动态修改。

安装部署

去官网下载Elasticsearch安装包,并解压到指定目录。

然后进入安装目录,启动命令:

./bin/elasticseatch

然后运行

curl localhost:9200

如果返回集群信息,说明安装成功。

build索引

ES提供了丰富的REST API

创建索引

直接运行

curl -XPUT "localhost:9200/index_test"

会创建名为index_test的索引,ES会根据插入的数据自动创建type与mapping,可以通过配置文件关闭ES的自动创建mapping功能。

也可以手动指定mapping,请求方式如下

curl -XPUT "localhost:9200/index_test" -d ' # 注意这里的'号
{
  "settings": {
    "index": {
      "number_of_replicas": "1", # 设置复制数
      "number_of_shards": "5" # 设置主分片数
    }
  },
  "mappings": { # 创建mapping
    "test_type": { # 在index中创建一个新的type(相当于table)
      "properties": {
        "name": { # 创建一个字段(string类型数据,使用普通索引)
          "type": "string",
          "index": "not_analyzed"
        },
        "age": {
          "type": "integer"
        }
      }
    }
  }
}

也可以通过json文件的方式指定mapping :

  • 创建一个扩展名为test_type.json的文件名,其中test_type就是mapping所对应的type名。
  • 在test_type.json中输入mapping信息。假设你的mapping如下:
{
  "test_type": { # 注意,这里的test_type与json文件名必须一致
      "properties": {
        "name": {
          "type": "string",
          "index": "not_analyzed"
        },
        "age": {
          "type": "integer"
        }
      }
    }
  }
  • 在$ES_HOME/config/路径下创建mappings/index_test子目录,这里的index_test目录名必须与我们要建立的索引名一致。将test_type.json文件拷贝到index_test目录下;
  • 创建index_test索引’’‘curl -XPUT “localhost:9200/index_test” # 注意,这里的富贵论坛索引名必须与mappings下新建的index_test目录名一致’’’。

可以通过请求

curl -XDELETE 'localhost:9200/index_test/_mapping/test_type'

删除mapping或者通过

curl -XGET 'localhost:9200/index_test/_mapping/test_type'

查看mapping。

可以通过请求

curl -XDELETE "localhost:9200/index_test"

删除该索引。

插入文档

可通过请求

curl -XPUT 'localhost:9200/index_test/test_type/1?pretty' -d ' # 这里的pretty参数的作用是使得返回的json显示地更加好看。1是文档的id值(唯一键)。
{
    "name": "zhangsan",
    "age" : "12"
}'

添加或更新文档。也可以通过id来删除文档

curl -XDELETE 'localhost:9200/index_test/test_type/1?pretty' 

查询操作

简单查询

查询单个文档

curl -XGET 'localhost:9200/index_test/test_type/1?pretty'。  

通过url地址来指定查询范围

  • localhost:9200/_search查询所有索引+所有类型
  • localhost:9200/index_test/_search在index_test索引中查询所有类型
  • localhost:9200/index_test/test_type/_search在index_test索引 test_type类型下 查询所有文档

搜索

查询指定属性

如在字段name中查找“一页书”;

{
    "query":{
        "match":{
            "name":"一页书"
        }
    }
}

结构化查询

如查询age在18-60之间的文档

{
    "query":{
        "range":{
		"age{
           		 "gte":18,
			 "lte":60
      	 		}
		}
	}
}

也支持filter操作,速度比query快,需要结合布尔类型使用。

多个条件联合查询

如查找name中包含“一页书“且age为18的文档。

{
    "query":{
	“bool”: {
		"must":[
			{
			 "match":{
            			"name":"一页书"
       				 }
			},
			{
			"filter":{
				"term"{
           		 		"age":18
		      	 		}
				}
			}
			]
		}
           }
}

支持must(与)、should(或)、must not等逻辑运算。

match、macth_phrase、multi_match与term的区别

  • match对会先对query进行分词,只要文档里面包含一个query中一个词就会被搜出来;
  • macth_phrase也会对query进行分词,但一个文档必须包含query里面所有的词才会被搜出来,可以通过slop参数降低这种约束;
{
  "query": {
    "match_phrase": {
        "content" : {
            "query" : "我的宝马多少马力",
            "slop" : 1
        }
    }
  }
}
  • multi_match对多个字段同时进行匹配;
  • term表示完全匹配,不对query进行分词,直接去匹配索引。

当然搜索是一项庞大的工程,要达到商业可用,还需要做很多事情,比如如何导入批量数据与流数据,Query纠错与改写,搜索排序,下拉推荐,个性化等,后面将一一进行介绍。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消