Elasticsearch安装及初步使用

背景:

一周前接到个紧急需求,项目PC端商品搜索要搞智能搜索,一个输入框,随便输入SPU码或者SKU码或者商品名称都能智能识别用户搜索的是啥,返回搜索结果。问了组长,这个要加入搜索引擎咯。这。。。我没搞过啊,产品还说要紧急上的,我想了下,先搞个临时方案吧,前端用正则识别用户输入的是中文或者英文时,传商品名称这个字段给我搜索,是数字的就传spu、sku给我。这个临时方案就是sql模糊搜索咯。然后上了这个,组长又说,搜索引擎还是要搞的,后面商品多了,搜索速度肯定有问题。那行吧,反正最近没需求,我研究下ES,预算时间是两周的,后来边看API边看网上大神们的实例,一周搞完了,现在勉强用着,不知道后面会不会有问题。下面开搞

项目里是在Linux下装的es,我这里在win10下装的,作为demo示例,额外加一下windows下安装ES:

1.下载并解压ES压缩包,我用的是6.4.3版本(7.0的版本需要设置密码):   https://www.elastic.co/cn/downloads/past-releases

(官网下载很慢,有个老哥整理了下,不全仅供参考:https://blog.csdn.net/weixin_37281289/article/details/101483434 )

2.下载中文分词器及安装,参考一下人家的: https://blog.csdn.net/liuzhenfeng/article/details/39404435

在ik的github:https://codeload.github.com/medcl/elasticsearch-analysis-ik/zip/master 里也有说明怎么操作:

Elasticsearch安装及初步使用_第1张图片

解释一下,第一步下载或者编辑ik插件。第一步有两个选择

1是到 https://github.com/medcl/elasticsearch-analysis-ik/releases 下载ik插件,注意ik的版本一定要和ES的版本相同,我使用的是6.4.3,下载的ik也要6.4.3。下载后在es解压目录下的plugins创建文件夹,重命名为ik,然后将下载的ik插件解压到刚才的ik文件夹里。

Elasticsearch安装及初步使用_第2张图片

2是直接使用elasticsearch-plugin去安装,这个没尝试,应该是Linux下的操作。

ES和ik都下载解压后,进入ES的bin文件夹,点击elasticsearch.bat启动ES,启动成功界面,且ik也加载了:

Elasticsearch安装及初步使用_第3张图片

 

浏览器输入:http://localhost:9200,

Elasticsearch安装及初步使用_第4张图片

ok,ES启动成功。

 

 

创建test索引,type为person,索引和type都是自定义:

Elasticsearch安装及初步使用_第5张图片

{
    "settings": {
        "analysis": {
            "analyzer": {
                "ik": {
                    "tokenizer": "ik_smart"
                }
            }
        }
    },
    "mappings": {
        "person": {
            "dynamic": true,
            "properties": {
                "name": {
                    "type": "text",
                    "analyzer": "ik_smart",
                    "search_analyzer": "ik_smart"
                },
                "author": {
                    "type": "text",
                    "analyzer": "ik_smart",
                    "search_analyzer": "ik_smart"
                }
            }
        }
    }
}

这里指定中文分词器和搜索字段分词方式为ik_smart,关于分词方式的了解,参考:https://www.jianshu.com/p/914f102bc174

删除索引 DELETE请求 http://localhost:9200/test

Elasticsearch安装及初步使用_第6张图片

 

下面配置项目:

ES版本用的是6.4.3,客户端用的是第三方的Jest  6.3

pom.xml引入:

                
		
			org.elasticsearch
			elasticsearch
			6.4.3
		
                
		
		    io.searchbox
		    jest
		    6.3.1
		

yml配置文件:

spring:
  elasticsearch:
    jest:
      uris: http://localhost:9200
      read-timeout: 5000
      connection-timeout: 5000

demo实体类:

public class Person {
    private String name;
    private String age;
    private String desc;
     
    //getter and setter...
}

增加文档内容,post  restful,json内容和实体类字段对应,可以指定ID去添加,如果没指定ID,由ES自动分配:

Elasticsearch安装及初步使用_第7张图片

 

查询所有插入的内容:

Elasticsearch安装及初步使用_第8张图片

短语查询,根据字段匹配过滤:

Elasticsearch安装及初步使用_第9张图片

查看索引的映射以及字段分词器 ,可以看到name和desc字段是按智能分词:

Elasticsearch安装及初步使用_第10张图片

查看索引/类型/id的某字段的分词情况 http://localhost:9200/test/person/1/_termvectors?fields=desc:

Elasticsearch安装及初步使用_第11张图片

 

ok,基础数据准备好了,下面结合java获取ES的数据,其实使用ES就像使用Redis这种no sql数据库一样:

@RestController
@RequestMapping("/test")
public class TestController {
        @GetMapping("/person/query")
	public List query() {
		//组装查询参数
		JSONObject json1=new JSONObject();
		JSONObject json2=new JSONObject();
		JSONObject json3=new JSONObject();
		
		json3.put("desc", "是");//查询的字段和值
		json2.put("match_phrase", json3);//匹配方式:短语匹配
		json1.put("query", json2);
		
		List personlList=new ArrayList();
		Search search = new Search.Builder(json1.toJSONString()).addIndex("test").addType("person").build();
		try {
			SearchResult result = jestClient.execute(search);
			List> hits = result.getHits(Person.class);
			for (Hit hit : hits) {
				Person person = hit.source;
				personlList.add(person);
			}
			return personlList;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
}

我使用的这个版本的ES的XContentBuilder的string()方法被废弃了,没研究怎么构造json,我直接用几个json对象去拼接查询参数了,有点尴尬。这里就是拼接好查询参数,指定index和type去查询,将查询结果拿出来转成对应的bean。对于匹配方式的介绍,可以在官网API,《Elasticsearch: 权威指南》了解下:https://www.elastic.co/guide/cn/elasticsearch/guide/current/search-in-depth.html

 

总体大概是上面这些内容了,总的来说,就是新建索引并设置mapping分词方式,然后将数据初始化到ES,然后再根据要查询的字段组装查询的json,用ES的客户端连接ES进行查询,最后将结果组装返回就可以啦。ES的客户端有好几种,  Java High Level Rest Client、 Java Low Level Rest Client、Jest。至于要使用哪种,看安装的ES版本以及自己操作喜欢...我是只找到Jest的看着简单点就用了。

我实际项目的思路是这样的,将商品的名称、标题、spu码、sku码、规格值等用户可能会搜索的信息用空格拼接到一个String字段,然后商品的ID作为文档的ID,商品详细信息的bean作为文档的主体。每天凌晨1点定时任务将上架的商品循环插入ES,在搜索的接口根据查询的字段拼接查询的json进行查询。在商品上架时就插入ES,下架商品就删除对应ID的文档,额,感觉有点像维护Reids缓存一样。

后面来点干货吧,一些工具类:

/**
 * 索引中数据的操作(增删改查)
 **/
public interface JestDataBaseService {

    /**
     * 单条删除
     */
    boolean deleteItem(String index, String type, String id);


    /**
     * 批量创建索引
     */
    void batchIndex(String index, String type, List list);

    /**
     * 单条索引(新增/更新)
     */
    void singleIndex(String index, String type, T t);

    /**
     * 指定索引ID
     */
    void singleIndexWithId(String index, String type, String id, T t);

    /**
     * 根据id查询
     */
    T queryById(String index, String type, String id, Class clazz);


}

 

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.rondaful.cloud.commodity.service.JestDataBaseService;

import java.io.IOException;
import java.util.List;

import javax.annotation.Resource;

import io.searchbox.client.JestClient;
import io.searchbox.client.JestResult;
import io.searchbox.core.Bulk;
import io.searchbox.core.Delete;
import io.searchbox.core.Get;
import io.searchbox.core.Index;

/**
 * elasticsearch通用操作
 **/
public class JestDataBaseServiceImpl implements JestDataBaseService {
	
	private final static Logger log = LoggerFactory.getLogger(JestDataBaseServiceImpl.class);

    @Resource
    private JestClient jestClient;

    @Override
    public boolean deleteItem(String index, String type, String id) {
        try {
            JestResult jestResult = jestClient.execute(new Delete.Builder(id).index(index).type(type).refresh(true).build());
            if (!jestResult.isSucceeded()) {
                log.error("deleteItem error:{}", jestResult.getErrorMessage());
            }
            return jestResult.isSucceeded();
        } catch (IOException e) {
            log.error("deleteItem error", e);
        }
        return false;
    }


    @Override
    public void batchIndex(String index, String type, List list) {
        try {
            Bulk.Builder builder = new Bulk.Builder();
            for (T t : list) {
                builder.addAction(new Index.Builder(t).index(index).type(type).build());
            }
            JestResult jestResult = jestClient.execute(builder.build());
            if (!jestResult.isSucceeded()) {
                log.error("batchIndex error:{}", jestResult.getErrorMessage());
            }
        } catch (IOException e) {
            log.error("batchIndex error", e);
        }
    }

    @Override
    public void singleIndex(String index, String type, T t) {
        try {
            JestResult jestResult = jestClient.execute(new Index.Builder(t).index(index).type(type).build());
            if (!jestResult.isSucceeded()) {
                log.error("singleIndex error:{}", jestResult.getErrorMessage());
            }
        } catch (IOException e) {
            log.error("singleIndex error", e);
        }
    }

    @Override
    public void singleIndexWithId(String index, String type, String id, T t) {
        try {
            JestResult jestResult = jestClient.execute(new Index.Builder(t).index(index).type(type).id(id).build());
            if (!jestResult.isSucceeded()) {
                log.error("singleIndexWithId error:{}", jestResult.getErrorMessage());
            }
        } catch (IOException e) {
            log.error("singleIndexWithId error", e);
        }
    }
    
    @Override
    public T queryById(String index, String type, String id, Class clazz) {
        T result = null;
        try {
            Get get = new Get.Builder(index, id).type(type).build();
            JestResult jestResult = jestClient.execute(get);
            result = jestResult.getSourceAsObject(clazz);
        } catch (IOException e) {
            log.error("queryById error", e);
        }
        return result;
    }

}

 

 

参考资料:

ES安装:http://www.mamicode.com/info-detail-2190390.html
分词器:https://www.jianshu.com/p/914f102bc174

Jest操作:https://blog.csdn.net/u010466329/article/details/75020956

Elasticsearch: 权威指南:https://www.elastic.co/guide/cn/elasticsearch/guide/current/index.html

Elasticsearch参考手册:https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html

小鱼的博客:http://www.gaowm.com/categories/Elasticsearch/

huitoudou的博客:https://blog.csdn.net/u014315200/article/details/78630284

docker上安装ES镜像:https://blog.csdn.net/weixin_38229356/article/details/84574416

 

 

 

 

你可能感兴趣的:(java学习笔记,elasticsearch)