2014-12-18 18 views
8

Tôi đang triển khai chỉ mục tự động hoàn thành trong ElasticSearch và đã gặp sự cố với sắp xếp/ghi điểm. Nói rằng tôi có chuỗi sau đây trong một chỉ số:Ghi điểm theo vị trí cụm từ trong Tìm kiếm Đàn hồi?

apple banana coconut donut 
apple banana donut durian 
apple donut coconut durian 
donut banana coconut durian 

Khi tôi tìm kiếm "bánh rán", tôi muốn các kết quả để được sắp xếp theo vị trí hạn như vậy:

donut banana coconut durian 
apple donut coconut durian 
apple banana donut durian 
apple banana coconut donut 

tôi không thể tìm hiểu cách thực hiện điều đó. Vị trí kỳ hạn không được tính vào logic điểm mặc định và tôi không thể tìm được cách để lấy nó trong đó. Có vẻ như một vấn đề đủ đơn giản mặc dù những người khác phải đã chạy vào điều này trước đây. Có ai đã tìm ra nó chưa?

Cảm ơn!

+0

Có thể điều này sẽ giúp http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/modules-advanced-scripting.html –

+0

Nó sẽ, tôi đã bắt đầu đi xuống con đường đó, cho đến khi tôi phát hiện ra rằng kịch bản không có quyền truy cập vào chuỗi tìm kiếm được mã hóa: ( – IGx89

Trả lời

0

Đây là giải pháp tôi đã kết thúc với, dựa trên câu trả lời Andrei và mở rộng để hỗ trợ nhiều thuật ngữ tìm kiếm và chấm điểm bổ sung dựa trên chiều dài của từ đầu tiên trong kết quả:

Đầu tiên, xác định các phân tích tùy chỉnh sau (nó giữ toàn bộ chuỗi như là một dấu hiệu duy nhất và lowercases nó):

"raw_analyzer": { 
    "type": "custom", 
    "filter": [ 
     "lowercase" 
    ], 
    "tokenizer": "keyword" 
} 

thứ hai, xác định bản đồ trường tìm kiếm của bạn như vậy ("tên" tên tôi của):

"name": { 
    "type": "string", 
    "analyzer": "english", 
    "fields": { 
     "raw": { 
      "type": "string", 
      "index_analyzer": "raw_analyzer", 
      "search_analyzer": "standard" 
     } 
    } 
}, 
"_nameFirstWordLength": { 
    "type": "long" 
} 

Thứ ba, khi Populating chỉ số sử dụng logic sau đây (tôi là trong C#) để cư trú:

_nameFirstWordLength = fi.Name.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries)[0].Length 

Cuối cùng, làm tìm kiếm của bạn như sau:

{ 
    "query":{ 
     "bool":{ 
     "must":{ 
      "match_phrase_prefix":{ 
       "name":{ 
        "query":"apple" 
       } 
      } 
     }, 
     "should":{ 
      "function_score":{ 
       "query":{ 
        "query_string":{ 
        "fields":[ 
         "name.raw" 
        ], 
        "query":"apple*" 
        } 
       }, 
       "script_score":{ 
        "script":"100/doc['_nameFirstWordLength'].value" 
       }, 
       "boost_mode":"replace" 
      } 
     } 
     } 
    } 
} 

Tôi đang sử dụng match_phrase_prefix để phần các đối sánh được hỗ trợ, chẳng hạn như "ap" khớp với "quả táo". Các bool phải/nên với query_string truy vấn thứ hai với name.raw cho một điểm số cao hơn để kết quả có tên bắt đầu với một trong các điều kiện tìm kiếm (trong mã của tôi tôi đang xử lý trước chuỗi tìm kiếm, chỉ cho truy vấn thứ hai, thêm "*" sau mỗi từ). Cuối cùng, gói truy vấn thứ hai đó trong kịch bản lệnh function_score sử dụng giá trị _nameFirstWordLength khiến kết quả được ghi bởi truy vấn thứ hai được sắp xếp thêm theo độ dài từ đầu tiên của chúng (ví dụ như Apple hiển thị trước Applebee).

5

Bạn có thể làm một phân loại tùy chỉnh, như thế này:

{ 
    "query": { 
    "match": { 
     "content": "donut" 
    } 
    }, 
    "sort": { 
    "_script": { 
     "script": "termInfo=_index['content'].get('donut',_OFFSETS);for(pos in termInfo){return _score+pos.startOffset};", 
     "type": "number", 
     "order": "asc" 
    } 
    } 
} 

Trong đó tôi vừa trở về các startOffset. Nếu bạn cần một cái gì đó khác, chơi với những giá trị và điểm gốc và đưa ra một giá trị thoải mái cho nhu cầu của bạn.

Hoặc bạn có thể làm một cái gì đó như thế này:

{ 
    "query": { 
    "function_score": { 
     "query": { 
     "match": { 
      "content": "donut" 
     } 
     }, 
     "script_score": { 
     "script": "termInfo=_index['content'].get('donut',_OFFSETS);for(pos in termInfo){return pos.startOffset};" 
     }, 
     "boost_mode": "replace" 
    } 
    }, 
    "sort": [ 
    { 
     "_score": "asc" 
    } 
    ] 
} 

Trong cả hai trường hợp bạn cần trong bản đồ của bạn cho rằng lĩnh vực cụ thể để có điều này:

"content": { 
    "type": "string", 
    "index_options": "offsets" 
} 

nghĩa index_options cần phải được thiết lập để offsets . Here biết thêm chi tiết về điều này.

+0

Cảm ơn Andrei! Câu trả lời tuyệt vời, toàn diện :). Điều đó hầu như sẽ hoạt động, ngoại trừ việc tôi đang sử dụng nguồn gốc, vì vậy nếu tôi tìm kiếm, nói "táo" nó sẽ không phải là thuật ngữ tìm kiếm trong chỉ mục (vì thuật ngữ được lập chỉ mục là "appl"). Nó cũng sẽ không lý tưởng cho các cụm từ tìm kiếm với nhiều từ, mặc dù tôi có thể làm việc xung quanh đó. – IGx89

+0

Trong trường hợp này - với stemmers - nó phải được đơn giản: chuyển đổi lĩnh vực của bạn trong một 'multi_field'. Thực hiện bất kỳ tìm kiếm nào bạn muốn trên phần gốc với một trường con và điểm tùy chỉnh ở trên phần không có gốc: "" nội dung ": { " loại ":" multi_field ", " trường ": { " nội dung ": { "loại": "chuỗi", "phân tích": "tiếng anh" }, "content_no_stemmer": { "loại": "chuỗi", "index_options": "offsets" } } } ' –

+0

Và tập lệnh sẽ thay đổi thành' "termInfo = _index ['content.content_no_stemmer']. Get ('apple', _ OFFSETS) ....' Điều này có phù hợp với bạn không? –

Các vấn đề liên quan