# How to do exact match with elasticsearch Chinese analysis plugin?

**URL:** <https://discuss.elastic.co/t/how-to-do-exact-match-with-elasticsearch-chinese-analysis-plugin/6386>\
**Category:** Elasticsearch\
**Created:** [January 15, 2012, 3:56pm UTC](https://discuss.elastic.co/t/how-to-do-exact-match-with-elasticsearch-chinese-analysis-plugin/6386 "2012-01-15T15:56:28Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![hau](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/hau/32/3232_2.png) [@hau](https://discuss.elastic.co/u/hau)\
**Post date:** [January 15, 2012, 3:56pm UTC](https://discuss.elastic.co/t/how-to-do-exact-match-with-elasticsearch-chinese-analysis-plugin/6386/1 "2012-01-15T15:56:28Z")

</div>

I was using the elasticsearch-analysis-smartcn plugin to perform full text  
search in Chinese.

I had a activerecord model Article which has a string content and many  
tags. Tags could be written in Chinese and I want to do exact match on the  
tags. I created this mapping inside of Article:

class Article \< ActiveRecord::Base  
include Tire::Model::Search  
include Tire::Model::Callbacks  
settings analysis: {  
filter: {  
smartcn\_word: {  
'type' =\> 'smartcn\_word'  
}  
},  
analyzer: {  
smart\_chinese: {  
'tokenizer' =\> 'smartcn\_sentence',  
'filter' =\> ['smartcn\_word'],  
'type' =\> 'smart\_chinese'  
}  
}  
} do  
mapping do  
indexes :content, type: 'string', analyzer: 'smart\_chinese'  
indexes :tags, type: 'string', index: 'not\_analyzed'  
end  
end  
end

where Article's tags is an array of strings.

I had an Article with tags: ["irresistible"] and another Article with tags:  
["恭喜发财"]. I wanted to search by exact matching on the tags. When I did

Article.search("resistible")

, it correctly returned zero match. But if I searched by

Article.search("发财")

, it returned one match. So, it's doing exact matching for English but a  
substring match in Chinese. How can I make it also do exact matching for  
Chinese?

Thanks for your help.

---

<div class="post-metadata">

**Author:** ![hau](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/hau/32/3232_2.png) [@hau](https://discuss.elastic.co/u/hau)\
**Post date:** [January 15, 2012, 4:02pm UTC](https://discuss.elastic.co/t/how-to-do-exact-match-with-elasticsearch-chinese-analysis-plugin/6386/2 "2012-01-15T16:02:18Z")

</div>

I was using the tire gem [https://github.com/karmi/tire](https://github.com/karmi/tire) in a rails  
application.

---

<div class="post-metadata">

**Author:** ![kimchy](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/kimchy/32/44952_2.png) [@kimchy](https://discuss.elastic.co/u/kimchy)\
**Post date:** [January 16, 2012, 12:09am UTC](https://discuss.elastic.co/t/how-to-do-exact-match-with-elasticsearch-chinese-analysis-plugin/6386/3 "2012-01-16T00:09:57Z")

</div>

I think you end up searching against the \_all field (the one that  
aggregates all the other fields). Try and specify explicitly that you want  
to search on the not analyzed tags.

On Sun, Jan 15, 2012 at 6:02 PM, hau [hoki.au@gmail.com](mailto:hoki.au@gmail.com) wrote:

> I was using the tire gem [GitHub - karmi/retire: A rich Ruby API and DSL for the Elasticsearch search engine](https://github.com/karmi/tire) in a rails  
> application.

---

<div class="post-metadata">

**Author:** ![hau](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/hau/32/3232_2.png) [@hau](https://discuss.elastic.co/u/hau)\
**Post date:** [January 16, 2012, 12:52am UTC](https://discuss.elastic.co/t/how-to-do-exact-match-with-elasticsearch-chinese-analysis-plugin/6386/4 "2012-01-16T00:52:17Z")

</div>

OK. Thanks. But could you help me by pointing out how that could be done,  
like how to not search on \_all?

I want to make the search match strings in the content field and exact  
matching on individual tag. So it's considered a match if a keyword appear  
inside Article.content OR if a keyword matches exactly one of the tags.

The tire call I used was Article.search(keyword). Or maybe that's not  
correct? Or did I not define the mapping correctly?

在 2012年1月16日 上午8:09，Shay Banon [kimchy@gmail.com](mailto:kimchy@gmail.com)写道：

> I think you end up searching against the \_all field (the one that  
> aggregates all the other fields). Try and specify explicitly that you want  
> to search on the not analyzed tags.
> 
> On Sun, Jan 15, 2012 at 6:02 PM, hau [hoki.au@gmail.com](mailto:hoki.au@gmail.com) wrote:
> 
> > I was using the tire gem [GitHub - karmi/retire: A rich Ruby API and DSL for the Elasticsearch search engine](https://github.com/karmi/tire) in a rails  
> > application.

--  
-hoki

---

<div class="post-metadata">

**Author:** ![hau](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/hau/32/3232_2.png) [@hau](https://discuss.elastic.co/u/hau)\
**Post date:** [January 17, 2012, 1:29am UTC](https://discuss.elastic.co/t/how-to-do-exact-match-with-elasticsearch-chinese-analysis-plugin/6386/5 "2012-01-17T01:29:33Z")

</div>

I changed the mapping to:

class Article \< ActiveRecord::Base  
include Tire::Model::Search  
include Tire::Model::Callbacks  
settings analysis: {  
filter: {  
smartcn\_word: {  
'type' =\> 'smartcn\_word'  
}  
},  
analyzer: {  
smart\_chinese: {  
'tokenizer' =\> 'smartcn\_sentence',  
'filter' =\> ['smartcn\_word'],  
'type' =\> 'smart\_chinese'  
}  
}  
} do  
mapping do  
indexes :content, type: 'string', analyzer: 'smart\_chinese'  
indexes :tags, type: 'string', index: 'not\_analyzed', include\_in\_all:  
false  
end  
end  
end

But when I did Article.search('发财'), it still matched the Article tagged  
with '恭喜发财'.

在 2012年1月16日 上午8:52，Ho-Ki Au [hoki.au@gmail.com](mailto:hoki.au@gmail.com)写道：

> OK. Thanks. But could you help me by pointing out how that could be  
> done, like how to not search on \_all?
> 
> I want to make the search match strings in the content field and exact  
> matching on individual tag. So it's considered a match if a keyword appear  
> inside Article.content OR if a keyword matches exactly one of the tags.
> 
> The tire call I used was Article.search(keyword). Or maybe that's not  
> correct? Or did I not define the mapping correctly?
> 
> 在 2012年1月16日 上午8:09，Shay Banon [kimchy@gmail.com](mailto:kimchy@gmail.com)写道：
> 
> I think you end up searching against the \_all field (the one that
> 
> > aggregates all the other fields). Try and specify explicitly that you want  
> > to search on the not analyzed tags.
> > 
> > On Sun, Jan 15, 2012 at 6:02 PM, hau [hoki.au@gmail.com](mailto:hoki.au@gmail.com) wrote:
> > 
> > > I was using the tire gem [GitHub - karmi/retire: A rich Ruby API and DSL for the Elasticsearch search engine](https://github.com/karmi/tire) in a rails  
> > > application.
> 
> --  
> -hoki

--  
-hoki

---

<div class="post-metadata">

**Author:** ![Matt1](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/matt1/32/2986_2.png) [@Matt1](https://discuss.elastic.co/u/Matt1)\
**Post date:** [January 17, 2012, 4:17am UTC](https://discuss.elastic.co/t/how-to-do-exact-match-with-elasticsearch-chinese-analysis-plugin/6386/6 "2012-01-17T04:17:08Z")

</div>

I'm not sure exactly what Article.search does: does it just call the  
endpoint, or can you use it to build a query, and in particular pick the  
type of query ([http://www.elasticsearch.org/guide/reference/query-dsl/](http://www.elasticsearch.org/guide/reference/query-dsl/))?

I've found that it's easier to first stick to the straight ES HTTP API, so  
you can figure out exactly how the query DSL works (it's non-trivial, and  
can be a little confusing), before trying to use one of the client  
libraries. I've been working through this same situation, but with the  
Python pyes library, also in a multilingual context, and the client can  
mask away some of the details of the API.

To be honest, I'm surprised that "恭喜发财" is parsed as a single term; I  
thought it would be split into "恭喜" and "发财", but I don't really know  
Chinese (haha). Going back to the first point, are you doing a term query  
([http://www.elasticsearch.org/guide/reference/query-dsl/term-query.html](http://www.elasticsearch.org/guide/reference/query-dsl/term-query.html))?

---

<div class="post-metadata">

**Author:** ![hau](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/hau/32/3232_2.png) [@hau](https://discuss.elastic.co/u/hau)\
**Post date:** [January 18, 2012, 2:08pm UTC](https://discuss.elastic.co/t/how-to-do-exact-match-with-elasticsearch-chinese-analysis-plugin/6386/7 "2012-01-18T14:08:31Z")

</div>

Despite reading your tips, I don't think I'm making progress. My original  
example was not complete. Let me elaborate.

I want to do search on a class of document which are JSON representation of  
Article objects. An Article could look like  
{  
title: "article subject line",  
tags: ["chinese", "food"],  
content: "article content"  
}

where I want to do:

1. substring match on title
2. exact match on tags
3. fulltext search on content  
And they are mostly Chinese, but could be a mix of Chinese and English

When I defined the mapping, I did  
settings analysis: {  
filter: {  
smartcn\_word: {  
'type' =\> 'smartcn\_word'  
}  
},  
analyzer: {  
smart\_chinese: {  
'tokenizer' =\> 'smartcn\_sentence',  
'filter' =\> ['smartcn\_word'],  
'type' =\> 'smart\_chinese'  
}  
}  
} do  
mapping do  
indexes :title, type: 'string', analyzer: 'keyword'  
indexes :content, type: 'string', analyzer: 'smart\_chinese'  
indexes :tags, type: 'string', analyzer: 'keyword'  
end  
end

which means I used the Chinese analyzer for content and keyword analyzer  
for title and tags.

When I performed the search, the query JSON looked like this (I got this  
from the logs):

'{"query":{"bool":{"should":[{"term":{"title":"search  
words"}},{"query\_string":{"query":"search  
words","default\_field":"content","default\_operator":"AND"}},{"terms":{"tag\_list":["search",  
"words"]}}],"minimum\_number\_should\_match":1}}}'

Fulltext search on the content worked fine, but I had problem getting the  
substring match on title and exact match on tags to work. They returned  
zero search result. It would only return results when I queried against  
\_all, i.e. if the query JSON was:

'{"query":{"query\_string":{"query":"search  
words","default\_operator":"AND"}}}'

I guess my question(s) is (or are):

1. Am I correct in using "term" search and keyword analyzer for substring  
match in the title field?
2. Am I correct in using the "terms" search and keyword analyzer for exact  
match for tags?
3. Am I correct in using bool with three "should" queries in it?

I am seeing other issues when I mixed Chinese and English, but I think that  
should go in another thread.

Please pardon me if my questions look dumb. I am new to elasticsearch (and  
lucene), but I did read through the its Guide and Tutorials. I'd  
appreciate it if someone who has more experience could help me figure this  
out.

在 2012年1月17日 下午12:17，Matt [matt.chu@gmail.com](mailto:matt.chu@gmail.com)写道：

> I'm not sure exactly what Article.search does: does it just call the  
> endpoint, or can you use it to build a query, and in particular pick the  
> type of query ([Elasticsearch Platform — Find real-time answers at scale | Elastic](http://www.elasticsearch.org/guide/reference/query-dsl/))?
> 
> I've found that it's easier to first stick to the straight ES HTTP API, so  
> you can figure out exactly how the query DSL works (it's non-trivial, and  
> can be a little confusing), before trying to use one of the client  
> libraries. I've been working through this same situation, but with the  
> Python pyes library, also in a multilingual context, and the client can  
> mask away some of the details of the API.
> 
> To be honest, I'm surprised that "恭喜发财" is parsed as a single term; I  
> thought it would be split into "恭喜" and "发财", but I don't really know  
> Chinese (haha). Going back to the first point, are you doing a term query (  
> [Elasticsearch Platform — Find real-time answers at scale | Elastic](http://www.elasticsearch.org/guide/reference/query-dsl/term-query.html))?

--  
-hoki

---

<div class="post-metadata">

**Author:** ![Matt1](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/matt1/32/2986_2.png) [@Matt1](https://discuss.elastic.co/u/Matt1)\
**Post date:** [January 19, 2012, 4:33am UTC](https://discuss.elastic.co/t/how-to-do-exact-match-with-elasticsearch-chinese-analysis-plugin/6386/8 "2012-01-19T04:33:25Z")

</div>

I'm still learning ES myself, so I'm not sure I can answer all of those  
questions, but here goes:

1. For the "term" search type, the field itself should be set to  
"not\_analyzed"; this should be set when you define the mapping. I _think_  
this also applies to "terms". There's an example  
on [http://www.elasticsearch.org/guide/reference/api/admin-indices-create-index.html](http://www.elasticsearch.org/guide/reference/api/admin-indices-create-index.html)  
which should point the way.
2. The bool looks fine, if ES doesn't throw a QueryParse exception (or  
whatever it's called)
3. This is a wild guess, but you might not be using the same analyzer for  
indexing as for searching? Try setting the "analyzer" field  
([http://www.elasticsearch.org/guide/reference/api/search/uri-request.html](http://www.elasticsearch.org/guide/reference/api/search/uri-request.html))

See if some/all of those helps?

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/elastic/original/3X/1/a/1ac57faf039f6b580b3f104ef42a2a89e41014de.png) [@system](https://discuss.elastic.co/u/system)\
**Post date:** [July 6, 2017, 3:42am UTC](https://discuss.elastic.co/t/how-to-do-exact-match-with-elasticsearch-chinese-analysis-plugin/6386/9 "2017-07-06T03:42:11Z")

</div>


