当前位置: 首页 > 图灵资讯 > 技术篇> ES(Elasticsearch)支持PB级全文搜索引擎入门教程

ES(Elasticsearch)支持PB级全文搜索引擎入门教程

来源:图灵教育
时间:2023-04-16 09:28:00

  全文搜索是最常见的需求,开源Elasticsearch(以下简称 Elastic)是目前全文搜索引擎的首选。

  它可以快速存储、搜索和分析大量数据。如维基百科全书,Stack Overflow、Github 都采用它。

  Elastic 底层是开源库Lucene。但是,你不能直接使用它 Lucene,必须自己编写代码来调用它的接口。Elastic 是 Lucene 包装,提供 REST API 开箱即用的操作接口,特别高效方便。

  在这里,我将从零告诉你如何使用它 Elastic 建立自己的全文搜索引擎。详细说明每一步,大家都能学会。一、安装

  Elastic 需要 Java 8 环境。如果你的机器还没有安装好 Java,可以参考本文,注意保证环境变量JAVA_HOME正确设置。

  安装完 Java,可以跟随官方文档安装 Elastic。直接下载压缩包比较简单。 $ wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.5.1.zip $ unzip elasticsearch-5.5.1.zip $ cd elasticsearch-5.5.1/

  然后,进入解压目录,操作下列命令,启动 Elastic。 $ ./bin/elasticsearch

  假如此时报错了"max virtual memory areas vm.maxmapcount [65530] is too low",操作下列命令。 $ sudo sysctl -w vm.max_map_count=262144

  若一切正常,Elastic 它将在默认的9200端口运行。此时,打开另一个命令行窗口,要求端口,您将得到解释信息。 $ curl localhost:9200 { "name" : "atntrTf", "cluster_name" : "elasticsearch", "cluster_uuid" : “tf9250XhQ6eee4h7YI11ana” "version" : { "number" : "5.5.1", "build_hash" : "19c13d0", "build_date" : "2017-07-18T20:44:24.823Z", "build_snapshot" : false, "lucene_version" : "6.6.0" }, "tagline" : "You Know, for Search" }

  在上述代码中,请求9200端口,Elastic 返回一个 JSON 对象,包括当前节点、集群、版本等信息。

  按下 Ctrl + C,Elastic 它将停止运行。

  默认情况下,Elastic 只允许本机访问,如果需要远程访问,可以修改 Elastic 安装目录的config/elasticsearch.yml文件,去掉network.host注释将其值改为0.0.0.0,然后重新启动 Elastic。 network.host: 0.0.0.0

  在上述代码中,设成0.0.0.0任何人都可以访问。不要这样设置在线服务,而是设置具体的服务 IP。 二、基本概念 2.1 Node 与 Cluster

  Elastic 本质上,它是一个允许多个服务器协同工作的分布式数据库,每个服务器可以运行多个服务器 Elastic 实例。

  单个 Elastic 例子称为节点(node)。一组节点形成一个集群(cluster)。 2.2 Index

  Elastic 处理后,将索引所有字段写入反向索引(Inverted Index)。搜索数据时,直接搜索索引。

  所以,Elastic 数据管理的顶层单位称为 Index(索引)。它是单个数据库的同义词。每个数据库 Index (即数据库)名称必须是小写。

  下面的命令可以查看当前节点的所有内容 Index。 $ curl -X GET 'http://localhost:9200/_cat/indices?v' 2.3 Document

  Index 内部单条的记录称为 Document(文档)。很多条 Document 构成了一个 Index。

  Document 使用 JSON 格式表示,以下是一个例子。 { "user": "冷雨轩", "title": "java工程师", "desc": “java全栈工程师” }

  同一个 Index 里面的 Document,不需要相同的结构(scheme),但最好保持相同,这有利于提高搜索效率。 2.4 Type

  Document 例如,可以分组weather这个 Index 可按城市(北京、上海)或气候(晴天、雨天)分组。这种分组叫做 Type,它是过滤虚拟逻辑分组的虚拟逻辑分组 Document。

  不同的 Type 应该有类似的结构(schema),举例来说,id字段不能在这个组中是字符串,而是在另一个组中是值。这与关系数据库的表不同。完全不同的数据(例如products和logs)应该存两个 Index,而不是一个 Index 里面的两个 Type(虽然可以)。

  下面的命令可以列出每个命令 Index 所包含的 Type。 $ curl 'localhost:9200/_mapping?pretty=true'

  根据规划,Elastic 6.x 只允许每个版本 Index 包含一个 Type,7.x 将完全删除版本 Type。 三、新建和删除 Index

  新建 Index,可以直接向 Elastic 服务器发出 PUT 请求。下面的例子是一个新名字weather的 Index。 $ curl -X PUT 'localhost:9200/weather'

  返回一个服务器 JSON 对象,里面的acknowledged字段表示操作成功。 { "acknowledged":true, "shards_acknowledged":true }

  然后,我们发出去 DELETE 请求,删除此 Index。 $ curl -X DELETE 'localhost:9200/weather' 四、中文分词设置

  首先,安装中文分词插件。这里使用ik,也可以考虑其他插件(如smartcn)。 $ ./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v5.5.1/elasticsearch-analysis-ik-5.5.1.zip

  上述代码安装在5.5.5上.插件1版,和 Elastic 5.5.1 配合使用。

  然后,重新启动 Elastic,新安装的插件将自动加载。

  然后,新建一个 Index,指定需要单词的字段。这一步根据数据结构而异,以下命令仅针对本文。基本上,所有需要搜索的中文字段都应该单独设置。 $ curl -X PUT 'localhost:9200/accounts' -d ' { "mappings": { "person": { "properties": { "user": { "type": "text", "analyzer": "ik_max_word", "search_analyzer": "ik_max_word" }, "title": { "type": "text", "analyzer": "ik_max_word", "search_analyzer": "ik_max_word" }, "desc": { "type": "text", "analyzer": "ik_max_word", "search_analyzer": "ik_max_word" } } } } }'

  在上述代码中,首先新建一个名称accounts的 Index,里面有个名字person的 Type。person有三个字段。 user title desc

  这三个字段都是中文,类型都是文本(text),因此,有必要指定中文分词器,而不是默认的英文分词器。

  Elastic 分词器叫analyzer。我们为每个字段指定分词器。 "user": { "type": "text", "analyzer": "ik_max_word", "search_analyzer": "ik_max_word" }

  在上述代码中,analyzer是字段文本的分词器,search_analyzer是搜索词的分词器。ik_max_word分词器是插件ik可以对文本进行最大数量的分词。 五、数据操作 5.1 新增记录

  向指定的 /Index/Type 发送 PUT 请求,就可以了 Index 里面有一个新的记录。例如,方向/accounts/person您可以通过发送请求来添加新的人员记录。 $ curl -X PUT 'localhost:9200/accounts/person/1' -d ' { "user": "冷雨轩", "title": "java工程师", "desc": “java全栈工程师” }'

  服务器返回 JSON 对象,会给出 Index、Type、Id、Version 等信息。 { "_index":"accounts", "_type":"person", "_id":"1", "_version":1, "result":"created", "_shards":{"total":2,"successful":1,"failed":0}, "created":true }

  如果你仔细看,你会发现请求路径是/accounts/person/1,最后的1是这条记录的 Id。它不一定是数字,任何字符串(例如abc)都可以。

  在添加新记录时,也可以不指定 Id,这时要改成 POST 请求。 $ curl -X POST 'localhost:9200/accounts/person' -d ' { "user": "java老鸟", "title": "java工程师", "desc": “java骨灰级开发” }'

  在上述代码中,方向/accounts/person发出一个 POST 请求,添加记录。此时,服务器返回 JSON 对象里面,_id字段是随机字符串。 { "_index":"accounts", "_type":"person", "_id":AV3QGFRC6jbb6k1p", "_version":1, "result":"created", "_shards":{"total":2,"successful":1,"failed":0}, "created":true }

  注意,如果没有先创建, Index(这个例子是accounts),直接执行上述命令,Elastic 它不会报错,而是直接生成指定的 Index。因此,打字时要小心,不要写错 Index 的名称。 5.2 查看记录

  向/Index/Type/Id发出 GET 请求,您可以查看此记录。 $ curl 'localhost:9200/accounts/person/1?pretty=true'

  请查看上述代码/accounts/person/1这条记录,URL 的参数pretty=true表示以易读格式返回。

  在返回的数据中,found字段表示查询成功,_source返回原始记录的字段。 { "_index" : "accounts", "_type" : "person", "_id" : "1", "_version" : 1, "found" : true, "_source" : { "user" : "冷雨轩", "title" : "java工程师", "desc" : “java全栈工程师” } }

  如果 Id 如果不正确,就找不到数据,found字段就是false。 $ curl 'localhost:9200/weather/beijing/abc?pretty=true' { "_index" : "accounts", "_type" : "person", "_id" : "abc", "found" : false } 5.3 删除记录

  删除记录就是发出 DELETE 请求。 $ curl -X DELETE 'localhost:9200/accounts/person/1'

  不要先删除这个记录,以后再使用。 5.4 更新记录

  使用更新记录 PUT 请求,重新发送数据。 $ curl -X PUT 'localhost:9200/accounts/person/1' -d ' { "user" : "冷雨轩", "title" : "java工程师", "desc" : “数据库管理,java软件开发” }' { "_index":"accounts", "_type":"person", "_id":"1", "_version":2, "result":"updated", "_shards":{"total":2,"successful":1,"failed":0}, "created":false }

  在上述代码中,我们将从上述代码中提取原始数据"java全栈工程师"改成"数据库管理,java软件开发"。 在返回结果中,几个字段发生了变化。 "_version" : 2, "result" : "updated", "created" : false

  可见,记录 Id 但是版本没有改变(version)从1变成2,操作类型(result)从created变成updated,created字段变成false,因为这次不是新记录。 六、数据查询 6.1 返回所有记录

  使用 GET 方法,直接请求/Index/Type/_search,所有记录都将返回。 $ curl 'localhost:9200/accounts/person/_search' { "took":2, "timed_out":false, "_shards":{"total":5,"successful":5,"failed":0}, "hits":{ "total":2, "max_score":1.0, "hits":[ { "_index":"accounts", "_type":"person", "_id":AV3QGFRC6jbb6k1p", "_score":1.0, "_source": { "user": "java老鸟", "title": "java工程师", "desc": “java骨灰级开发” } }, { "_index":"accounts", "_type":"person", "_id":"1", "_score":1.0, "_source": { "user" : "冷雨轩", "title" : "java工程师", "desc" : “数据库管理,java软件开发” } } ] } }

  在上述代码中,返回结果took字段表示操作耗时(单位为毫秒),timed_out字段表示是否超时,hits字段表示命中记录,子字段的含义如下。 total:本例为两个返回记录数。 max_score:本例是最高匹配度1.0。 hits:由返回记录组成的数组。

  在返回记录中,每个记录都有一个_score默认情况下,表示匹配程序的字段是按字段降序排列的。 6.2 全文搜索

  Elastic 查询很特别,使用自己的查询语法,要求 GET 带有数据体的请求。 $ curl 'localhost:9200/accounts/person/_search' -d ' { "query" : { "match" : { "desc" : "软件" }} }'

  Match使用上述代码 查询时,指定的匹配条件是desc包含在字段中"软件"这个词。返回结果如下。 { "took":3, "timed_out":false, "_shards":{"total":5,"successful":5,"failed":0}, "hits":{ "total":1, "max_score":0.28582606, "hits":[ { "_index":"accounts", "_type":"person", "_id":"1", "_score":0.28582606, "_source": { "user" : "冷雨轩", "title" : "java工程师", "desc" : “数据库管理,java软件开发” } } ] } }

  Elastic 一次默认返回10个结果可以通过size更改此设置的字段。 $ curl 'localhost:9200/accounts/person/_search' -d ' { "query" : { "match" : { "desc" : "管理" }}, "size": 1 }'

  上述代码规定,每次只返回一个结果。

  还可以通过from指定位移的字段。 $ curl 'localhost:9200/accounts/person/_search' -d ' { "query" : { "match" : { "desc" : "管理" }}, "from": 1, "size": 1 }'

  以上代码指定,从位置1开始(默认从位置0开始),只返回一个结果。 6.3 逻辑运算

  若有多个搜索关键字, Elastic 认为它们是or关系。 $ curl 'localhost:9200/accounts/person/_search' -d ' { "query" : { "match" : { "desc" : "软件 开发" }} }'

  搜索上面的代码软件 or 系统。

  若要执行多个关键词and必须使用布尔查询进行搜索。 $ curl 'localhost:9200/accounts/person/_search' -d ' { "query": { "bool": { "must": [ { "match": { "desc": "软件" } }, { "match": { "desc": "java" } } ] } } }' 七、参考链接 ElasticSearch 官方手册 A Practical Introduction to Elasticsearch

  (完)