首页 文章

如何使用ElasticSearch搜索单词的一部分

提问于
浏览
93

我最近开始使用ElasticSearch,我似乎无法让它搜索一个单词的一部分 .

示例:我在我的couchdb中有三个索引在ElasticSearch中索引的文档:

{
  "_id" : "1",
  "name" : "John Doeman",
  "function" : "Janitor"
}
{
  "_id" : "2",
  "name" : "Jane Doewoman",
  "function" : "Teacher"
}
{
  "_id" : "3",
  "name" : "Jimmy Jackal",
  "function" : "Student"
}

所以现在,我想搜索包含“Doe”的所有文件

curl http://localhost:9200/my_idx/my_type/_search?q=Doe

这不会返回任何命中 . 但是,如果我搜索

curl http://localhost:9200/my_idx/my_type/_search?q=Doeman

它确实返回一个文件(John Doeman) .

我尝试过设置不同的分析器和不同的过滤器作为索引的属性 . 我也试过使用完整的查询(例如:

{
  "query": {
    "term": {
      "name": "Doe"
    }
  }
}

但似乎没有任何作用 .

当我搜索“Doe”时,如何让ElasticSearch找到John Doeman和Jane Doewoman?

UPDATE

我尝试使用nGram标记器和过滤器,就像Igor提出的那样,如下所示:

{
  "index": {
    "index": "my_idx",
    "type": "my_type",
    "bulk_size": "100",
    "bulk_timeout": "10ms",
    "analysis": {
      "analyzer": {
        "my_analyzer": {
          "type": "custom",
          "tokenizer": "my_ngram_tokenizer",
          "filter": [
            "my_ngram_filter"
          ]
        }
      },
      "filter": {
        "my_ngram_filter": {
          "type": "nGram",
          "min_gram": 1,
          "max_gram": 1
        }
      },
      "tokenizer": {
        "my_ngram_tokenizer": {
          "type": "nGram",
          "min_gram": 1,
          "max_gram": 1
        }
      }
    }
  }
}

我现在遇到的问题是每个查询都返回所有文档 . 有什么指针吗?关于使用nGram的ElasticSearch文档并不是很好......

9 回答

  • 4

    我也在使用nGram . 我使用标准tokenizer和nGram作为过滤器 . 这是我的设置:

    {
      "index": {
        "index": "my_idx",
        "type": "my_type",
        "analysis": {
          "index_analyzer": {
            "my_index_analyzer": {
              "type": "custom",
              "tokenizer": "standard",
              "filter": [
                "lowercase",
                "mynGram"
              ]
            }
          },
          "search_analyzer": {
            "my_search_analyzer": {
              "type": "custom",
              "tokenizer": "standard",
              "filter": [
                "standard",
                "lowercase",
                "mynGram"
              ]
            }
          },
          "filter": {
            "mynGram": {
              "type": "nGram",
              "min_gram": 2,
              "max_gram": 50
            }
          }
        }
      }
    }
    

    让我们找到最多50个字母的单词部分 . 根据需要调整max_gram . 在德语中,单词可以变得非常大,所以我将其设置为高 Value .

  • 1

    使用前导和尾随通配符进行搜索对于大型索引来说会非常慢 . 如果您希望能够通过单词前缀进行搜索,请删除前导通配符 . 如果你真的需要在一个单词的中间找到一个子字符串,那么你最好使用ngram tokenizer .

  • -7

    我认为没有必要改变任何映射 . 尝试使用 query_string ,它是完美的 . 所有方案都适用于默认的标准分析器:

    我们有数据:

    {"_id" : "1","name" : "John Doeman","function" : "Janitor"}
    {"_id" : "2","name" : "Jane Doewoman","function" : "Teacher"}
    

    Scenario 1:

    {"query": {
        "query_string" : {"default_field" : "name", "query" : "*Doe*"}
    } }
    

    响应:

    {"_id" : "1","name" : "John Doeman","function" : "Janitor"}
    {"_id" : "2","name" : "Jane Doewoman","function" : "Teacher"}
    

    Scenario 2:

    {"query": {
        "query_string" : {"default_field" : "name", "query" : "*Jan*"}
    } }
    

    响应:

    {"_id" : "1","name" : "John Doeman","function" : "Janitor"}
    

    Scenario 3:

    {"query": {
        "query_string" : {"default_field" : "name", "query" : "*oh* *oe*"}
    } }
    

    响应:

    {"_id" : "1","name" : "John Doeman","function" : "Janitor"}
    {"_id" : "2","name" : "Jane Doewoman","function" : "Teacher"}
    

    编辑 - 与 spring 数据弹性搜索相同的实现https://stackoverflow.com/a/43579948/2357869

    再解释一下query_string如何比其他更好https://stackoverflow.com/a/43321606/2357869

  • 22

    在不更改索引映射的情况下,您可以执行简单的前缀查询,该查询将执行您希望的部分搜索

    即 .

    {
      "query": { 
        "prefix" : { "name" : "Doe" }
      }
    }
    

    https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-prefix-query.html

  • 0

    尝试使用此处描述的解决方案:Exact Substring Searches in ElasticSearch

    {
        "mappings": {
            "my_type": {
                "index_analyzer":"index_ngram",
                "search_analyzer":"search_ngram"
            }
        },
        "settings": {
            "analysis": {
                "filter": {
                    "ngram_filter": {
                        "type": "ngram",
                        "min_gram": 3,
                        "max_gram": 8
                    }
                },
                "analyzer": {
                    "index_ngram": {
                        "type": "custom",
                        "tokenizer": "keyword",
                        "filter": [ "ngram_filter", "lowercase" ]
                    },
                    "search_ngram": {
                        "type": "custom",
                        "tokenizer": "keyword",
                        "filter": "lowercase"
                    }
                }
            }
        }
    }
    

    要解决磁盘使用问题和过长的搜索项问题,请使用短8个字符长的ngram(配置为:"max_gram":8) . 要搜索超过8个字符的术语,请将搜索转换为布尔AND查询,以查找该字符串中每个不同的8个字符的子字符串 . 例如,如果用户搜索大码(10个字符的字符串),搜索将是:

    “arge ya和arge yar and rge yard .

  • 9

    如果要实现自动完成功能,那么Completion Suggester是最简洁的解决方案 . 下一个blog post包含一个非常清晰的描述如何工作 .

    换句话说,它是一个称为FST的内存数据结构,它包含有效的建议,并针对快速检索和内存使用进行了优化 . 从本质上讲,它只是一个图表 . 例如,包含单词 hotelmarriotmercuremunchenmunich 的FST将如下所示:

    enter image description here

  • 72

    Elasticsearch具有通配符查询,可以在这种情况下使用,并且是最简单的查询 . 它将返回两个匹配的文档

  • 55

    你可以使用正则表达式 .

    { "_id" : "1", "name" : "John Doeman" , "function" : "Janitor"}
    { "_id" : "2", "name" : "Jane Doewoman","function" : "Teacher"  }
    { "_id" : "3", "name" : "Jimmy Jackal" ,"function" : "Student"  }
    

    如果您使用此查询:

    {
      "query": {
        "regexp": {
          "name": "J.*"
        }
      }
    }
    

    你将给出他们的名字以“J”开头的所有数据 . 考虑你只想接收他们的名字以“man”结尾的前两个记录,这样你就可以使用这个查询:

    {
      "query": { 
        "regexp": {
          "name": ".*man"
        }
      }
    }
    

    如果你想接收名字中存在“m”的所有记录,你可以使用这个查询:

    {
      "query": { 
        "regexp": {
          "name": ".*m.*"
        }
      }
    }
    

    这对我有用 . 我希望我的答案适合解决你的问题 .

  • 0

    没关系 .

    我不得不看看Lucene的文档 . 似乎我可以使用通配符! :-)

    curl http://localhost:9200/my_idx/my_type/_search?q=*Doe*
    

    诀窍!

相关问题