最近产品需要一个搜索商城中的商品的功能,于是接触了一下Elastic Search。虽然久仰它的大名,但一直都没有真正用过。这次稍微摸索了一下,顺便记录下来,说不定哪天就真的需要用上了。
安装
首先需要下载Elastic Search,我选择了.zip格式的安装包,下载地址在这里。下载完成后就拿到了一个5.2.2版本的Elastic Search的安装包,只需要解压即可使用。因为我喜欢把软件安装到主目录的app目录下,所以我用的命令是
1 | cd /home/liutos/app |
主目录下的installer是我习惯的用来存放软件的安装包的位置。解压后生成了一个名为elasticsearch-5.2.2的新目录。在这个目录下有一个名为bin的子目录,只需要进入该目录运行其中的elasticsearch文件即可,实例命令为
1 | cd elasticsearch-5.2.2/bin |
为了让Elastic Search可以不占用当前的终端,添加了-d选项,使其以后台进程(daemon)的方式运行。Elastic Search需要JVM才能运行,在执行上面的命令之前请各位自行准备好Java程序的运行环境。成功启动后,Elastic Search默认会监听9200端口,可以通过浏览器访问http://localhost:9200来确认Elastic Search是否正常启动了
使用
创建索引
遵照官方文档中的指导,先创建一个索引以便后续向这个索引中添加文档。假设要创建的索引是为商品准备的,取名为products,可以通过如下的命令创建出来
1 | curl -X PUT 'http://localhost:9200/products' |
创建成功后Elastic Search的响应结果为
1 | {"acknowledged":true,"shards_acknowledged":true} |
如果希望Elastic Search返回更可读的形式,可以添加?pretty
参数到上面的URL的末尾。
文档的增删查改
索引已经创建了,就可以创建文档了。Elastic Search的文档是对象形式的,假设现在要创建的对象的类型为product,示例命令如下
1 | curl -X POST 'http://localhost:9200/products/product' --data ' |
在我的机器上,Elastic Search的响应结果为
1 | {"_index":"products","_type":"product","_id":"AVqpZHmVckriR6iVcbaW","_version":1,"result":"created","_shards":{"total":2,"successful":1,"failed":0},"created":true} |
其中名为”_id”的字段的值为Elastic Search自动为这份新写入的文档分配的ID,通过这个ID可以从Elastic Search中取出这份文档,示例命令如下
1 | curl 'http://localhost:9200/products/product/AVqpZHmVckriR6iVcbaW?pretty' |
相当的RESTful的接口路径,也许你已经猜到了,删除一个文档的代码就是将请求的GET方法替换为DELETE。是的,示例代码如下
1 | curl -X DELETE 'http://localhost:9200/products/product/AVqpZHmVckriR6iVcbaW?pretty' |
再次查找刚才的ID的文档时,响应结果中的”_found”字段的值就已经变成了false了。关于修改文档的方法,请参考官方手册中的章节。
搜索
准备数据
最简单的搜索接口的使用就是通过浏览器访问http://localhost:9200/products/_search这个地址了。在我的机器上,看到的页面内容为如下的JSON字符串
1 | { |
为了方便接下来的演示,先通过Elastic Search的_bulk接口向其批量创建文档数据,示例代码如下
1 | curl -X POST 'http://localhost:9200/_bulk?pretty' --data-binary '@docs' |
其中docs文件中的内容为
1 | {"create": {"_index": "products", "_type": "product", "_id": 1}} |
尽管这里是一个文本文件,但是根据官方文档的说法,此处需要使用curl的二进制模式来发送数据,否则会报错。
个性化搜索
如果希望找到《失控》这本书的信息,那么可以根据书名进行查找,示例代码如下
1 | curl 'http://localhost:9200/products/_search?q=name:失控' |
Elastic Search提供了许多的搜索选项,如果全部通过URL中的query string来传递将会非常难以构造。为此,可以使用Elastic Search提供的基于HTTP body的参数传递方式,示例代码如下
1 | curl -X GET 'http://localhost:9200/products/_search' --data '{"query": {"match": {"name": "失控"}}}' |
Elastic Search支持相当丰富的搜索选项,这里不逐一介绍了,大家可以从官方文档的这里开始翻看。本来想在Chrome的POSTMAN插件中试验搜索功能的,结果当我选定了GET方法后,就不需要我提交HTTP body了,因此还是用curl进行演示。回到正题,如果我们搜索的是一个“站”字,那么Elastic Search会吐出两个结果,此处可以使用搜索接口的from
和size
参数,分别控制返回的内容取自搜索结果中的哪一个片段。例如想要取出结果中的第二个,可以使用下列代码
1 | curl -X GET 'http://localhost:9200/products/_search?pretty' --data '{"from": 1, "size": 1, "query": {"match": {"name": "站"}}}' |
通过结合使用from
和size
参数,可以实现许多应用中所要求的分页功能。在我厂的业务场景中,商品信息还是很多的,不可能全部放入到Elastic Search中作为文档数据存储,Elastic Search只是负责提供搜索出来的商品ID即可,之后再通过商品ID从原来的商品的数据库中按照顺序取出对应的完整的商品信息。因此,在搜索Elastic Search时实际上只需要商品的ID就足够了,可以通过Elastic Search提供的_source
字段控制接口吐出的内容,示例代码如下
1 | curl -X GET 'http://localhost:9200/products/_search?pretty' --data '{"query": {"match_all": {}}, "_source": ["_id"]}' |
这样在吐出的内容中_source
字段的值就会是一个空对象,应用程序只需要取每一个hits数组中的记录的”_id”字段即可。这样做的目的是减少Elastic Search通过网络传输了一部分毫无必要的数据,略微优化一下网络开销
全文完