Con người thường không dùng chính xác từ muốn search và đôi khi cần thực hiện chuẩn hóa từ khóa của user hay query ví dụ -ed hay -ing trong tiếng Anh. Analysis thực hiện việc này cho cả documnent lẫn câu query trước khi thực hiện search.
Việc phân tích tất cả các documents tốn rất nhiều thời gian nên thông thường thực hiện trước, quá trình này gọi là indexing đánh chỉ mục. Các tài liệu đã phân tích được lưu trữ dưới định dạng format dành riêng cho việc tìm kiếm gọi là index.
Ví dụ tài liệu có từ 'Searching' sẽ được lowercase và bỏ -ing thành 'search'. Các term đã phân tích (analyzed term) như vậy được lưu trong index. Query sau đó cũng được thực hiện tương tự, nếu trùng khớp term 'search' trong document đã được indexed thì document kết quả sẽ được trả về.
Quá trình phân tích có 3 phần: (việc parse phân tách tài liệu như html, pdf để lấy text không nằm trong phạm vi của analysis).
Giả sử đã có kết quả parse từ HTML
Building a top-notch search engine
Việc đầu tiên là character filters, ví dụ trên là html-strip bỏ các tag HTML
Building a top-notch search engine
Sau đó là tokenizer (splitter), chia tách string thành những token (thẻ, dấu). Ví dụ với standard tokenizer thì - dash coi là word boundary nên tách làm 2, trong khi whitespace chỉ quan tâm đến khoảng trắng nên sẽ không tách top-notch. Một vài phương pháp tokenizing khác như n-gram sẽ thực hiện chia đều. Giả sử dash - là chia tách từ sau khi phân tách kết quả như sau:
[Building] [a] [top] [notch] [search] [engine]
Cuối cùng token filters sẽ thực hiện các xử lý thêm trên các token, ví dụ loại bỏ các hậu tố gọi là stemming, chuyển sang chữ thường. Sau quá trình này sẽ có được:
[build] [a] [top] [notch] [search] [engine]
Kết hợp giữa tokenizer và zero hay nhiều các filter sẽ được analyzer. ES cung cấp một số các analyzer chuẩn ví dụ Standand bao gồm Standard tokenizer và các filter Standard, Lowercase và Stop token filter.
Analyzer có thể phức tạp hơn như kiểm tra chính tả hay từ đồng nghĩa trong trường hợp tìm kiếm 'search' hay 'find'. ES cũng cung cấp 1 số các stemming algorithm như Porter Stem, Snowball, và KStem. Ngoài ra có thể tạo các custom analyzer. Ví dụ custom analyzer sau là tương đương Standard analyzer
{ "settings": { "analysis": { "analyzer": { "default": { "type": "custom", "tokenizer": "standard", "filter": ["standard", "lowercase", "stop", "kstem"] } } } } }
OK giờ vào phần chính.
Autocomplete & phrase suggester with Elasticsearch
Thực hiện install nhanh môi trường để test.
1.1 Install Java SDK
1.1.1 Download archive file from Oracle
cd /opt wget link-to- jdk-7u55-linux-i586.tar.gz tar xzf jdk-7u55-linux-i586.tar.gz cd /opt/jdk1.7.0_55/
1.1.2 Config alternatives --config
alternatives --config java There are 1 programs which provide 'java'. Selection Command ----------------------------------------------- * 1 /usr/lib/jvm/jre-1.6.0-openjdk/bin/java Enter to keep the current selection[+], or type selection number: 2
1.1.3 Install alternatives -- install
alternatives --install /usr/bin/java java /opt/jdk1.7.0_55/bin/java 2
1.1.4 Check installed version
java –version java version "1.7.0_55" Java(TM) SE Runtime Environment (build 1.7.0_55-b13) Java HotSpot(TM) Client VM (build 24.55-b03, mixed mode) Setup environmental variables export JAVA_HOME=/opt/jdk1.7.0_55
1.2 Installation
1.2.1 Get and unpack ES zip file
cd /usr/local/src wget https://download.elastic.co/elasticsearch/elasticsearch/elasticsearch-1.5.1.tar.gz tar -xvf elasticsearch-1.5.1.tar.gz mv ./elasticsearch-1.5.1 /usr/local/elasticsearch
1.2.2 Install with yum
# Add elasticsearch.repo in /etc/yum.repos.d/ [elasticsearch-1.5] name=Elasticsearch repository for 1.5.x packages baseurl=http://packages.elasticsearch.org/elasticsearch/1.5/centos gpgcheck=1 gpgkey=http://packages.elasticsearch.org/GPG-KEY-elasticsearch enabled=1 yum install elasticsearch chkconfig --add elasticsearch
File config của Elasticsearch /etc/elasticsearch/elasticsearch.yml
1.2.3 Config IP for remote access
# [/etc/elasticsearch/elasticsearch.yml] # Elasticsearch, by default, binds itself to the 0.0.0.0 address, and listens # on port [9200-9300] for HTTP traffic and on port [9300-9400] for node-to-node #network.bind_host: ["192.168.19.137", "localhost"] # # Publish host network.publish_host: 192.168.19.137 #/etc/init.d/elasticsearch restart # # [/etc/sysconfig/iptables] # [nano /etc/sysconfig/iptables] # Check firewall not block port 9200 /etc/sysconfig/iptables ... -A INPUT -p icmp -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT -A INPUT -p tcp -m tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT -A INPUT -p tcp -m tcp --dport 443 -m state --state NEW,ESTABLISHED -j ACCEPT -A INPUT -p tcp -m tcp --dport 9200 -m state --state NEW,ESTABLISHED -j ACCEPT -A INPUT -j REJECT --reject-with icmp-host-prohibited -A FORWARD -j REJECT --reject-with icmp-host-prohibited ... #/etc/init.d/network restart
1.3 Install plugins for ES
1.4 JDBC plugin for ES
1.4.1 Install JDBC plugin
# Install JDBC plugin ./bin/plugin --install jdbc --url http://xbib.org/repository/org/xbib/elasticsearch/plugin/elasticsearch-river-jdbc/1.5.0.4/elasticsearch-river-jdbc-1.5.0.4-plugin.zip cd /usr/local/src wget http://cdn.mysql.com/Downloads/Connector-J/mysql-connector-java-5.1.35.tar.gz tar -xvf mysql-connector-java-5.1.35.tar.gz cp mysql-connector-java-5.1.35/mysql-connector-java-5.1.35-bin.jar /usr/share/elasticsearch/plugins/jdbc/ /etc/init.d/elasticsearch restart
1.4.2 Create index 'sample'
curl-XPOST http://localhost:9200/sample -d '{ "settings": { "analysis": { "tokenizer": { "ngram_tokenizer": { "type": "nGram", "min_gram": "2", "max_gram": "3", "token_chars": ["letter", "digit"] } }, "analyzer": { "ngram_analyzer": { "tokenizer": "ngram_tokenizer" } } } }, "mappings": { "test": { "_source": { "enabled": true }, "_all": { "enabled": true, "analyzer": "ngram_analyzer" }, "properties": { "id": { "type": "integer", "index": "not_analyzed" }, "name": { "type": "string", "index": "analyzed", "analyzer": "ngram_analyzer" } } } } }'
1.4.3 Using JDBC river List toàn bộ river
curl -XGET 'http://[host]:9200/_river/_search?q=*&pretty'
Xóa river
curl -XDELETE 'http://[host]:9200/_river/[river-name]'
Suspend và resume river
curl -XPOST 'http://[host]:9200/_river/jdbc/[river-name]/_suspend|_resume'
Tạo river mới
curl -XPUT 'http://localhost:9200/_river/[river-name]/_meta' -d '{ "type": "jdbc", "jdbc": { "driver": "com.mysql.jdbc.Driver", "url": "jdbc:mysql://[host]:[port]/[db]", "user": "[user]", "password": "[password]", "sql": "SELECT * FROM [table]", "index": "[index]", "type": "[type]" } }'
Có thể dùng options "schedule": "00 00 01 * * ?" để chạy cronjob
1.5 Updating the mappings and settings of an existing index
Kiểm tra index _settings và type _mapping
curl -XGET 'http://[endpoint]:9200/[index]/_settings' curl -XGET 'http://[endpoint]:9200/[index]/[type]/_mapping'
Để update index phải thực hiện _close index và sau đó _open index
# Close index curl -XPOST 'http://[endpoint]:9200/[index]/_close' #{ # "acknowledged": true #} # Updating settings (verb = PUT) curl -XPUT 'http://[endpoint]:9200/[index]/_settings' -d '{ "index": { "analysis": { "filter": { … }, "analyzer": { "did_you_mean": { … }, "autocomplete": { … }, "default": { … } } } } }' # Open index again curl -XPOST 'http://[endpoint]:9200/[index]/_open'
1.6 Autocomplete & phrase suggester
- Kiểm tra settings của index hiện tại.
- Cần tạo settings cho analysic và 2 analyzer là autocomplete và didYouMean. Giả sử index đã chứa các token như sau
[quick] [brown] [fox] [jump] [over] [lazy] [dog]
Khi user thực hiện tìm kiếm thông thường với quick, nếu query match với token trong index, document sẽ được trả về. Trong trường hợp autocomplete query không phải là một full word mà là các query như:
[q] [qu] [qui] [quic] [quick]
Việc thực hiện autocomplete có thể bằng 2 cách sau:
- Sử dụng Prefix query
- n-gram
1.6.1 Prefix query
quick OR quack OR quote OR quarter
Nếu trong index có rất nhiều term thỏa mãn thì quá trình này trở nên khá khó sử dụng và nhiều khi lỗi. Do có thể match ở giữa term như ball trong baseball nên Prefix query thường đi kèm Wildcard query. Thử sử dụng Prefix query với điều chỉnh settings thử nghiệm analyzer đơn giản như sau:
curl -XPUT 'http://[endpoint]:9200/[index]/_settings' -d '{ "index": { "analysis": { "filter": { "stemmer_filter": { "type": "stemmer", "language": "english" }, "shingle_filter": { "max_shingle_size": "5", "min_shingle_size": "2", "type": "shingle" }, "stopwords_filter": { "type": "stop", "stopwords": ["_english_"] } }, "analyzer": { "did_you_mean": { "filter": ["lowercase"], "char_filter": ["html_strip"], "type": "custom", "tokenizer": "standard" }, "autocomplete": { "char_filter": ["html_strip"], "type": "custom", "tokenizer": "standard", "filter": ["lowercase", "shingle_filter"] }, "default": { "char_filter": ["html_strip"], "type": "custom", "tokenizer": "standard", "filter": ["lowercase", stopwords_filter", stemmer_filter"] } } } } }'
Giải thích settings.
- default - Là analyzer mặc định để search document trong index. Analyzer này sử dụng các filter như sau
- html_strip - loại bỏ tag HTML, decode các ký tự encode cho HTML.
- lowercase - bỏ case-sensitive bằng cách lower-cased.
- stopwords - loại bỏ các stop words, like is, a, all, an, etc.
- stemmer - finish cleaning text và token.
- did_you_mean - một simple analyzer dùng lowercase filter, html_strip.
- autocomplete - dùng filter custom từ shingle với config min và max shingle size: shingle filter là một filter thực hiện tách từ. Test thử analyzer như sau:
curl -XGET 'http://[endpoint]:9200/[index]/_analyze?pretty&analyzer=[analyzer]&text=[input]' Kiểm tra _mapping của type curl -XGET 'http://[endpoint]:9200/[index]/[type]/_mapping' # Output { "[index]": { "mappings": { "[type]": { "properties": { "actors": { "type": "string" }, "description": { "type": "string" }, "directors": { "type": "string" }, "producers": { "type": "string" }, "title_en": { "type": "string" }, "title_vn": { "type": "string" } } } } } }
Giả sử cần tạo thêm properties cho mapping
- Tạo mới did_you_mean bằng cách copy title_en, title_vn, actors, description copy did_you_mean
- Tạo mới autocomplete bằng cách copy title_en, title_vn, actors copy autocomplete
Thực hiện update lại _mapping như sau
curl -XDELETE 'http://[endpoint]:9200/[index]/[type]/_mapping curl -XPUT 'http://[endpoint]:9200/[index]/[type]/_mapping?ignore_conflicts=true' -d '{ "[index]": { "properties": { "autocomplete": { "type": "string", "analyzer": "autocomplete" }, "actors": { "type": "string", "copy_to": [ "autocomplete" ] }, "description": { "type": "string" }, "directors": { "type": "string", "copy_to": [ "autocomplete" ] }, "producers": { "type": "string" }, "title_en": { "type": "string", "copy_to": [ "autocomplete" ] }, "title_vn": { "type": "string", "copy_to": [ "autocomplete" ] } } } }'
Thực hiện index lại và search với pattern như sau:
curl -XPOST 'http://[endpoint]:9200/[index]/[type]/_search' -d '{ "size": 0, "aggs": { "autocomplete": { "terms": { "size": 5, "field": "autocomplete", "order": { "_count": "desc" }, "include": { "pattern": "termi.*" } } } }, "query": { "prefix": { "autocomplete": { "value": "termi" } } } }' # Output { "took": 168, "timed_out": false, "_shards": { "total": 5, "successful": 5, "failed": 0 }, "hits": { "total": 10, "max_score": 0, "hits": [] }, "aggregations": { "autocomplete": { "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0, "buckets": [ { "key": "terminator", "doc_count": 6 }, { "key": "terminal", "doc_count": 4 }, { "key": "terminator the", "doc_count": 4 }, { "key": "terminator the sarah", "doc_count": 4 }, { "key": "terminator the sarah connor", "doc_count": 4 } ] } } }
Test với tiếng Việt vẫn chạy tạm được. Ví dụ autocomplete cho "dò" ra kết quả tuy nhiên nếu autocomplete cho "don" lẫn "dong" đều không ra kết quả tiếng Việt » chủ yếu ra tên của các actor Hàn Quốc như Dong Gun, Dong Wook. Nếu autocomplete cho từ chỉ có của tiếng Việt ví dụ "kh" thì có kết quả tiếng Việt trả về.
1.6.2 n-gram
[q] [qu] [qui] [quic] [quick]
Trong ES có các token và các token filter có thể thực hiện tách word thành n-gram.
1.6.3 Tokenizer vs. Token Filter
Trong document của ES ghi n-gram tokenizer thuộc loại nGram tuy nhiên đây không phải là n-gram cần dùng vì tokenizer này chia string thành n-gram token mà không phải là word-based n-gram. Thử với config mặc định (min_gram=1 và max_gram=2).curl -XGET 'http://[endpoint]:9200/[index]/_analyze?pretty=&analyzer=ngram&text= wx yz' # Output [w] [x] [ ] [y] [z] [wx] [x ] [ y] [yz]
1.6.4 NGram vs. Edge NGram
n-gram thực hiện chia string thành các token cho tất cả các letter trong work ví dụ min = 1, max = 2 cho brown
[b] [r] [o] [w] [n] [br] [ro] [ow] [wn]
Trong khi đó edge n-gram chỉ sinh 2 token tính từ bắt đầu work
[b] [br]
Nếu muốn sinh đủ tokens cho word brown thì phải tăng max_gram lên 5
1.6.5 Fields
Multi field của ES cho phép một file index theo những cách khác nhau.
"title": { "type": "string", "fields": { "raw": { "type": "string", "index": "not_analyzed" }, "autocomplete": { "type": "string", "analyzer": "autocomplete" } } }
Ví dụ title mặc định là full-text field sẽ được analyzed trong khi titlte.raw không analyzed và title.autocomplete dùng analyzer là autocomplete. (Xem Multi-fields).
1.6.6 search_analyzer vs. index_analyzer
Thông thường chỉ cần chỉ định analyzer có nghĩa là search analyzer và index_analyzer thực hiện chung một quá trình như nhau. Giả sử index_analyzer sử dụng edge n-gram với min_gram=3, max_gram=20, khi đó "elasticsearch" sẽ generate như token sau:
[ela] [elas] [elast] [elasti] [elastic] [elastics] [elasticse] [elasticsea] [elasticsear] [eleasticsearc] [elasticsearch]
Khi thực hiện search query trên field vừa tạo, nếu search chỉ với "elastic" sẽ có kết quả trả về mà không cần thực hiện edge n-gram trên query. Nếu thực hiện edged n-gram trên query sẽ ra tokens
[ela] [elas] [elast] [elasti] [elastic]
Khi đó khả năng "elastic" sẽ match với document khác ngoài document ở trên. Ví dụ "ela" sẽ match với "ela" khi index cho "elapsed" mặc dù "elapsed" hoàn toàn không có chứa elastic.
[ela] [elap] [elaps] [elapse] [elapsed]
1.6.7 n-gram size & query strategy
Sử dụng n-gram=1 không hữu ích lắm vì hầu hết đơn ký tự (letter) đều match hết các document » min_gram=2.
1.6.8 Suggester
Ví dụ thực hiện kiểm tra suggester như sau
{ "suggest": { "did_you_mean": { "text": "toy stery", "phrase": { "field": "suggest", "highlight": { "pre_tag": "<em>", "post_tag": "</em>" } } } }, "size": 0, "query": { "multi_match": { "query": "toy stery", "fields": ["title_vn^3", "title_en^3", "actors"] } } } # Output { "took": 496, "timed_out": false, "_shards": { "total": 5, "successful": 5, "failed": 0 }, "hits": { "total": 43, "max_score": 0, "hits": [] }, "suggest": { " did_you_mean": [{ "text": "toy stery", "offset": 0, "length": 9, "options": [{ "text": "toy steve", "highlighted": "toy <em>steve</em>", "score": 0.00015490633 }, { "text": "toy story", "highlighted": "toy <em>story</em>", "score": 0.00009656796 }, { "text": "toy starr", "highlighted": "toy <em>starr</em>", "score": 0.00006153661 }, { "text": "toy storm", "highlighted": "toy <em>storm</em>", "score": 0.000052716518 }, { "text": "toy stacy", "highlighted": "toy <em>stacy</em>", "score": 0.00003965827 }] }] } }
1.7 Install vn-tokenizer
Thực hiện install plugin Elasticsearch-analysic-vietnamese tại https://github.com/duydo/elasticsearch-analysis-vietnamese
bin/plugin --url https://dl.dropboxusercontent.com/u/1598491/elasticsearch-analysis-vietnamese-0.1.1.zip --install analysis-vietnamese #--install analysis-vietnamese #-> Installing analysis-vietnamese... #Trying https://dl.dropboxusercontent.com/u/1598491/elasticsearch-analysis-#vietnamese-0.1.1.zip... #Downloading ........................................................................#....................................................................................#....................................................................................#.......................................DONE #Installed analysis-vietnamese into /usr/share/elasticsearch/plugins/analysis-#vietnamese
Kiểm tra vi_analyzer bằng một số tên phim tiếng Việt như sau:
curl -XGET 'http://[endpoint]:9200/[index]/_analyze?pretty=&analyzer=vi_analyzer&text=sát%20thủ%20tự%20do' # Output { "tokens": [ { "token": "sát thủ", "start_offset": 0, "end_offset": 7, "type": "word", "position": 1 }, { "token": "tự do", "start_offset": 7, "end_offset": 12, "type": "word", "position": 2 } ] } tuyển tập: thiếu lâm tự » [tuyển tập] [thiếu lâm] [tự] đội bóng thiếu lâm » [đội] [bóng] [thiếu lâm] gián điệp hai mang » [gián điệp] [hai] [mang] dòng máu anh hùng » [dòng] [máu] [anh hùng] đông phương bất bại » [đông] [phương] [bất] [bại] đại nội thị vệ » [đại nội] [thị vệ]
Đánh giá tokenizer này chưa thực sự tốt tuy nhiên vẫn có cải tiến đáng kể so với standard. Sửa lại analyzer didYouMean dùng vi_analyzer
# Close index curl -XPOST 'http://[endpoint]:9200/[index]/_close' curl -XPUT 'http://[endpoint]:9200/[index]/_settings' -d '{ "index": { "analysis": { "filter": { "stemmer_filter": { "type": "stemmer", "language": "english" }, "autocomplete_filter": { "max_shingle_size": "5", "min_shingle_size": "2", "type": "shingle" }, "stopwords_filter": { "type": "stop", "stopwords": ["_english_"] }, "ngram_filter": { "type": "ngram", "min_gram": 2, "max_gram": 15 } }, "analyzer": { "did_you_mean": { "filter": ["lowercase"], "char_filter": ["html_strip"], "type": "custom", "tokenizer": "vi_tokenizer" }, "autocomplete": { "filter": ["lowercase", "autocomplete_filter"], "char_filter": ["html_strip"], "type": "custom", "tokenizer": "standard" }, "default": { "filter": ["lowercase", "stopwords_filter", "stemmer_filter"], "char_filter": ["html_strip"], "type": "custom", "tokenizer": "standard" } } } } }' # Open index curl -XPOST 'http://[endpoint]:9200/[index]/_open'
No comments:
Post a Comment