ElasticSearch关于自定义分词器模糊检索数字+字母 | 您所在的位置:网站首页 › 英语模糊查询 › ElasticSearch关于自定义分词器模糊检索数字+字母 |
一 、前言
之前的系统由于一些表的数据已经达到1~2百万行的数据了,而且还在与日俱增,一些条件比较复杂的检索,已经明显感觉到比较慢,影响用户的使用体验。所以引入的ElasiticSearch进行检索优化,效果还是比较好的。因为之前都没有怎么涉及到模糊检索这一块需求,只是为了速度引入了ES。更之前的认知,是知道引入ik分词器之后能对中文进行很好的分词,也进行过相关的模糊检索都没有出现问题。 二、问题直到有个业务需要对电话号码进行模糊检索,发现只能精准检索,通过 @Field(type = FieldType.Long,analyzer="simple") @Field(type = FieldType.Text,analyzer="simple")非字母分词也还是不能检索出来。 之后还有对字母+数字的字段模糊检索的需求,更是没有办法实现。 三、解决思路首先想到的思路是,之前数据录入ES的时候,都是以Json的形式。 bulkRequest.add(new IndexRequest("apply_car").source(JSONUtil.toJsonStr(ocApplyCars.get(j)), XContentType.JSON));所以觉得是不是因为字符串不能数字分词的原因,所以尝试着在网上找到了,以实体类录入的方式。 写一个mapper,继承ES的Repository,相当于mysql省去了xml,可以直接写需要调用的方法,具体的命名规则可以去查看官方的文档,简单说就是操作命令加上字段。 public interface EsApplyCarMapper extends ElasticsearchRepository { List findByNumber(String number); }在实体类中标住各字段,一开始出现的标注分词器也是在这一步实现的,选择字段的属性之类。 @Id @Field(type = FieldType.Text) @TableId(value = "apply_car_id", type = IdType.ASSIGN_ID) @JsonSerialize(using = ToStringSerializer.class) private Long applyCarId;直接就可以调用es的mapper方法,添加和检索数据了。 @Resource private EsApplyCarMapper esApplyCarMapper; public AjaxResult add(OcApplyCar applyCar) { esApplyCarMapper.save(applyCar); return AjaxResult.success(); }但是并没有收到效果,对于数字和字母混数字的检索还是不能进行模糊匹配。 之后在网上看到可以自定义分词器,对需要的针对进行自己想要的分词建立索引。直接拿了找到的设置,在kibana里进行了检验,是行之有效的。 PUT /apply_car { "settings": { "index.max_ngram_diff":10, "analysis": { "analyzer": { "my_ngram_analyzer": { "tokenizer": "my_ngram_tokenizer" } }, "tokenizer": { "my_ngram_tokenizer": { "type": "ngram", "min_gram": 1, "max_gram": 10, "token_chars": [ "letter", "digit" ] } } } }, "mappings": { "properties": { "number":{ "type": "text", "analyzer": "my_ngram_analyzer" }, "phone":{ "type": "text", "analyzer": "my_ngram_analyzer" }, "createName":{ "type": "text" } } } }但是一直没有想明白怎么把这个自定义的分词器引入到程序里面,在网上也没有找到比较详细的资料说这方面的事情。所以首先我想到的是先在代码里建立好对应的index索引之后,在对这个索引在kibana上进行settings配置上,但是并没有起到效果。继续在网上查看之后,需要建立settings.json和mapping.json进行代码的配置,在实体类上使用@Mapping和@Setting。 @Document(indexName = "apply_car", shards = 1, replicas = 0, type="ApplyCar") @Setting(settingPath = "/json/settings/ApplyCarSettings.json") @Mapping(mappingPath = "json/mappings/ApplyCarMapping.json") { "index.max_ngram_diff": 10, "analysis": { "analyzer": { "my_ngram_analyzer": { "tokenizer": "my_ngram_tokenizer" } }, "tokenizer": { "my_ngram_tokenizer": { "type": "ngram", "min_gram": 1, "max_gram": 10, "token_chars": [ "letter", "digit" ] } } } } { "properties": { "number":{ "type": "text", "analyzer": "my_ngram_analyzer" }, "phone":{ "type": "text", "analyzer": "my_ngram_analyzer" }, "createName":{ "type": "text" } } }最后还是没有起效。网上大部分的帖子也就到这里为止了。没有更详细和后续的操作和说法,只是有的说settings.json里面要加index的,有mapping里面要加type的名字的才能对应上,还有个问题就是@Document里的type我在7.6.1里面使用已经显示是个过时的方法了。 四、最后一步可能有系统的学过ES整合spingboot的知道要在创建index的时候就要对他进行设置了,而不是靠动态的注解自动注入进去。但是我之前真不知道也没有想到,只知道可以在录入的时候设置max_result_window。网上居然找了半天也没有针对这个方面的说法,可能真是大家都知道这个事情,只有我遇到了这个“问题”。 IndexOperations indexOperations = elasticsearchOperations.indexOps(OcApplyCar.class); MappingBuilder builder = new MappingBuilder(elasticsearchOperations.getElasticsearchConverter()); String mapping = builder.buildPropertyMapping(OcApplyCar.class); Document document = Document.parse(mapping); try { if (indexOperations.exists()) { indexOperations.delete(); log.info( "索引已经存在,重新创建。"); } indexOperations.create(); indexOperations.putMapping(document); log.info("索引创建成功..."); } catch (Exception e) { log.error("索引创建失败.原因:{}",e); }或者是直接和设置max_result_window一样,直接一大串写下来也是可以的,然后updateSettingRequest也行。 五、结语仅以此文记录在ElasticSearch中遇到的自定义分词的问题。 |
今日新闻 |
推荐新闻 |
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 |