Cách tìm kiếm một phần của từ bằng Tìm kiếm đàn hồi


128

Gần đây tôi đã bắt đầu sử dụng ElasticSearch và dường như tôi không thể tìm kiếm nó cho một phần của từ.

Ví dụ: Tôi có ba tài liệu từ couchdb của tôi được lập chỉ mục trong ElasticSearch:

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

Vì vậy, bây giờ, tôi muốn tìm kiếm tất cả các tài liệu có chứa "Doe"

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

Điều đó không trả lại bất kỳ lượt truy cập. Nhưng nếu tôi tìm kiếm

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

Nó trả về một tài liệu (John Doeman).

Tôi đã thử đặt các máy phân tích khác nhau và các bộ lọc khác nhau làm thuộc tính cho chỉ mục của mình. Tôi cũng đã thử sử dụng một truy vấn đầy đủ (ví dụ:

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

) Nhưng dường như không có gì để làm việc.

Làm cách nào tôi có thể làm cho Tìm kiếm đàn hồi tìm thấy cả John Doeman và Jane Doewoman khi tôi tìm kiếm "Doe"?

CẬP NHẬT

Tôi đã cố gắng sử dụng mã thông báo và bộ lọc nGram, như đề xuất của Igor, như thế này:

{
  "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
        }
      }
    }
  }
}

Vấn đề tôi gặp phải bây giờ là mỗi truy vấn trả về TẤT CẢ các tài liệu. Bất kỳ con trỏ? Tài liệu về Tìm kiếm đàn hồi khi sử dụng nGram không tuyệt vời ...


9
không có gì lạ, bạn habe min / max ngram được đặt thành 1, vì vậy 1 chữ cái :)
Martin B.

Câu trả lời:


85

Tôi cũng đang sử dụng nGram. Tôi sử dụng mã thông báo tiêu chuẩn và nGram giống như một bộ lọc. Đây là thiết lập của tôi:

{
  "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
        }
      }
    }
  }
}

Hãy để bạn tìm các phần từ lên đến 50 chữ cái. Điều chỉnh max_gram khi bạn cần. Trong các từ tiếng Đức có thể trở nên thực sự lớn, vì vậy tôi đặt nó thành một giá trị cao.



Đó có phải là những gì bạn nhận được từ các cài đặt của chỉ mục hay đó là những gì bạn đăng lên elaticsearch để định cấu hình nó?
Tomas Jansson

Đây là một POST để cấu hình Elaticsearch.
roka

Tôi không chắc chắn với các phiên bản hiện tại của Elasticsearch, nhưng nên đề cập đến nó trong các tài liệu: elastic.co/guide/en/elasticsearch/reference/current/index.html
Roka

1
@JimC Tôi đã không sử dụng ElasticSearch trong ít nhất 7 năm, vì vậy tôi không biết những thay đổi hiện tại của dự án.
roka

63

Tìm kiếm với các ký tự đại diện hàng đầu và dấu vết sẽ cực kỳ chậm trên một chỉ mục lớn. Nếu bạn muốn có thể tìm kiếm theo tiền tố từ, hãy xóa ký tự đại diện hàng đầu. Nếu bạn thực sự cần tìm một chuỗi con ở giữa một từ, bạn sẽ tốt hơn khi sử dụng ngram tokenizer.


14
Igor nói đúng. Ít nhất là loại bỏ hàng đầu *. Để biết ví dụ NGram ElasticSearch, hãy xem ý chính này: gist.github.com/988923
karmi

3
@karmi: Cảm ơn ví dụ hoàn chỉnh của bạn! Có lẽ bạn muốn thêm nhận xét của mình như một câu trả lời thực tế, đó là những gì nó đã làm việc cho tôi và những gì tôi muốn nâng cao.
Fabian Steeg

54

Tôi nghĩ rằng không cần phải thay đổi bất kỳ ánh xạ. Hãy thử sử dụng query_ chuỗi , nó hoàn hảo. Tất cả các kịch bản sẽ hoạt động với bộ phân tích tiêu chuẩn mặc định:

Chúng tôi có dữ liệu:

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

Cảnh 1:

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

Phản ứng:

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

Kịch bản 2:

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

Phản ứng:

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

Kịch bản 3:

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

Phản ứng:

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

EDIT - Thực hiện tương tự với tìm kiếm đàn hồi dữ liệu mùa xuân https://stackoverflow.com/a/43579948/2357869

Thêm một lời giải thích làm thế nào query_ chuỗi tốt hơn những cái khác https://stackoverflow.com/a/43321606/2357869


3
tôi nghĩ rằng đây là cách dễ nhất
Esgi Dendyanri

Đúng . Tôi đã thực hiện trong dự án của tôi.
Opster Elaticsearch Pro-Vijay

Làm thế nào để bao gồm nhiều lĩnh vực để tìm kiếm?
Shubham A.

thử này: - { "truy vấn": { "QUERY_STRING": { "lĩnh vực": [ "nội dung", "name"], "truy vấn": "Đây VÀ rằng"}}}
Opster Elasticsearch Pro-Vijay


14

không thay đổi ánh xạ chỉ mục của bạn, bạn có thể thực hiện một truy vấn tiền tố đơn giản sẽ thực hiện tìm kiếm một phần như bạn đang hy vọng

I E.

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

https://www.elastic.co/guide/en/elSTERearch/reference/civerse/query-dsl-prefix-query.html


bạn có thể thực hiện tìm kiếm đa lĩnh vực bằng cách sử dụng truy vấn tiền tố?
batmaci

Cảm ơn, chỉ là những gì tôi đang tìm kiếm! Bất kỳ suy nghĩ về tác động hiệu suất?
Vingtoft

6

Hãy thử giải pháp với được mô tả ở đây: Tìm kiếm chuỗi con chính xác trong 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"
                }
            }
        }
    }
}

Để giải quyết vấn đề sử dụng đĩa và các vấn đề quá dài hạn tìm kiếm ngắn 8 ký tự dài ngrams được sử dụng (cấu hình với: "max_gram": 8 ). Để tìm kiếm các cụm từ có nhiều hơn 8 ký tự, hãy biến tìm kiếm của bạn thành một boolean VÀ truy vấn tìm kiếm mọi chuỗi con 8 ký tự riêng biệt trong chuỗi đó. Ví dụ: nếu người dùng tìm kiếm khoảng sân rộng (chuỗi 10 ký tự), tìm kiếm sẽ là:

"Arge ya VÀ arge yar VÀ sân rge .


2
liên kết chết, vui lòng sửa
DarkMukke

Tôi đã tìm kiếm một cái gì đó như thế này trong một thời gian. Cảm ơn bạn! Bạn có biết bộ nhớ chia tỷ lệ với min_grammax_gramcó vẻ như nó sẽ phụ thuộc tuyến tính vào kích thước của các giá trị trường và phạm vi minmax. Làm thế nào nhăn mặt khi sử dụng một cái gì đó như thế này?
Glen Thompson

Ngoài ra, có bất kỳ lý do nào mà ngrambộ lọc qua mã thông báo không? có thể bạn không chỉ có nó như là một tokenizer và sau đó áp dụng một bộ lọc chữ thường ... index_ngram: { type: "custom", tokenizer: "ngram_tokenizer", filter: [ "lowercase" ] }Tôi đã thử nó và có vẻ như để cho kết quả tương tự bằng cách sử dụng api thử nghiệm phân tích
Glen Thompson

2

Nếu bạn muốn thực hiện chức năng tự động hoàn thành, thì Hoàn thành Suggester là giải pháp gọn gàng nhất. Các bài đăng blog tiếp theo chứa một mô tả rất rõ ràng làm thế nào điều này hoạt động.

Nói cách khác, đó là cấu trúc dữ liệu trong bộ nhớ được gọi là FST chứa các đề xuất hợp lệ và được tối ưu hóa để truy xuất nhanh và sử dụng bộ nhớ. Về cơ bản, nó chỉ là một biểu đồ. Ví dụ, và FST có chứa các từ hotel, marriot, mercure, munchenmunichsẽ trông như thế này:

nhập mô tả hình ảnh ở đây


2

bạn có thể sử dụng regrec.

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

nếu bạn sử dụng truy vấn này:

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

bạn sẽ cung cấp cho tất cả dữ liệu tên của họ bắt đầu bằng "J". Người kiểm tra bạn muốn nhận chỉ hai bản ghi đầu tiên rằng tên của họ kết thúc bằng "người đàn ông" để bạn có thể sử dụng truy vấn này:

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

và nếu bạn muốn nhận tất cả các bản ghi trong tên của chúng tồn tại "m", bạn có thể sử dụng truy vấn này:

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

Điều này làm việc cho tôi. Và tôi hy vọng câu trả lời của tôi phù hợp để giải quyết vấn đề của bạn.


1

Sử dụng wilcards (*) để ngăn chặn điểm số


1
Bạn có thể thêm chi tiết cho câu trả lời của bạn? Cung cấp một mã mẫu hoặc tham chiếu đến tài liệu về những gì nó làm.
Cray

0

Tôi đang sử dụng cái này và tôi đã làm việc

"query": {
        "query_string" : {
            "query" : "*test*",
            "fields" : ["field1","field2"],
            "analyze_wildcard" : true,
            "allow_leading_wildcard": true
        }
    }

-6

Đừng bận tâm.

Tôi đã phải xem tài liệu Lucene. Có vẻ tôi có thể sử dụng ký tự đại diện! :-)

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

lừa


11
Xem câu trả lời @imotov. Việc sử dụng các ký tự đại diện sẽ không có quy mô tốt.
Mike Munroe

5
@Idx - Xem cách trả lời của riêng bạn. Downvotes đại diện cho chất lượng và mức độ liên quan của một câu trả lời. Bạn có thể dành một phút để chấp nhận câu trả lời đúng? Ít nhất người dùng mới sẽ biết ơn bạn.
async chờ

3
Đủ các downvote. OP đã làm rõ câu trả lời tốt nhất là gì bây giờ. +1 để chia sẻ những gì dường như là câu trả lời tốt nhất trước khi ai đó đăng bài tốt hơn.
s.Daniel 17/03/2015
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.