• Elasticsearch实现类似 like '?%' 搜索


     

    在做搜索的时候,下拉联想词的搜索肯定是最常见的一个场景,用户在输入的时候,要自动补全词干,说得简单点,就是以...开头搜索,如果是数据库,一句SQL就很容易实现,但在elasticsearch如何实现呢?

    大家可能会立马想到用elasticsearch自带的suggest功能,确实,在一些初级应用场景,特别是数据量比较少的情况下,suggest可以快速简易的解决问题。

    在数据量比较大的时候,性能有待提高,而且遇到复杂场景,suggest就会显得力不从心,看下面一个需求:


    1、下拉结果需要根据城市过滤   

    2、下拉结果需要根据拼音搜索、首字母搜索、中文拼音混合搜索等

    如果使用suggest,是不是无从下手?

    下面我介绍另外二种实现的方式,这二种试更加灵活,以上二个问题皆可解决,由于篇幅,我将在其他章节具体讲解拼音+混合搜索。

    一、基于正则表达式搜索

    要点:索引的时候,使用"keyword"作为tokenizer,把整个文本当作一个term。

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    curl -XPUT localhost:9200/search_words_index -d '{

       "settings" : {

          "refresh_interval" "5s",

          "number_of_shards" 1,

          "number_of_replicas" 1,

          "analysis" : {           

        "analyzer": {

                    "myAnalyzer": {

                        "type""custom",

                        "tokenizer""keyword",

                        "filter": ["lowercase"]

                    }

                }

           }

        },

        "mappings": {      

            "search_words_type": {          

                "properties": {  

                    "words": {

                         "type""string",

                         "index""analyzed",

                          "indexAnalyzer" "myAnalyzer"                         

                        }

                    }

                }

            }

        }

    }'

    搜索的时候,可使用queryStringQuery或者wildcardQuery实现正则表达式查询,啰嗦一句,queryStringQuery与wildcardQuery的区别是,wildcardQuery是一种低级查询,不会进行analyzer的,而queryStringQuery则会,更具体区别的可参考官网资料。

    下面以queryStringQuery方式为例进行说明,关键代码:

    String reg=/key.*/;

    QueryBuilders.queryStringQuery(reg).field("words").analyzer("myAnalyzer"));

    这种方式的优点是简单,索引空间占用也不大,效率也还可以,但我更推荐下面的一种式,性能会更佳。

    二、基于edge-ngram分词法

    这种方式是典型的以空间换时间的做法,唯一的缺点是会加大索引开销,索引数据的时间也会加长,但这种开销都是在索引阶段,并不会影响查询阶段,只要有足够的磁盘和内存空间,效率还是很不错的。

    要点:索引阶段使用edge-ngram分词,按金字塔式的分割成独立的term。如下:

    中华人民共和国

    中华人民共和

    中华人民共

    中华人民

    中华人

    中华

    索引如下:

    复制代码

    curl -XPUT localhost:9200/search_words_index -d '{
       "settings" : {
          "refresh_interval" : "5s",
          "number_of_shards" : 1,
          "number_of_replicas" : 1,
          "analysis" : {            
               "filter": { 
                   "edge_ngram_filter": { 
                        "type": "edge_ngram",
                        "min_gram": 1,
                        "max_gram": 30
               },
    "analyzer": {
                    "myAnalyzer": {
                        "type": "custom",
                        "tokenizer": "keyword",
                        "filter": ["edge_ngram_filter","lowercase"]
                    }
                }
           }
        },
        "mappings": {       
            "search_words_type": {           
                "properties": {   
                    "words": {
                         "type": "string",
                         "index": "analyzed",
                          "indexAnalyzer" : "myAnalyzer"                          
                        }
                    }
                }
            }
        }
    }'

    复制代码

    搜索的时候,直接使用term查询,如果比较复杂的情况下,如要按拼音、中文繁体转换等,则使用matchQuery,先对关键字进行一次分析。

    QueryBuilders.termQuery("words", key);//低级查询,速度快

    或者

    QueryBuilders.matchQuery("words", key).analyzer("xxx");//可指定分词器来分析关键字

    这种搜索结果保证一定是以..开头,因为在索引阶段就已经把term限定了。

    注意:以上java代码示例都是基于spring-data-elasticsearch框架。

  • 相关阅读:
    python3(二十七)property
    python3(二十六)slots
    python3(二十五) getClassInfo
    python3(二十四) subClas
    python3(二十三)classInstance
    python3(二十二) oop
    python3(二十一) pip
    python3(二十) module
    python3(十九)Partial func
    python3(十八)decorator
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13317460.html
Copyright © 2020-2023  润新知