Azure search: Japanese search for Katakana and Hiragana - azure-cognitive-search

I have created search index with ja.microsoft analyzer and it works fine as far as I am searching for characters in katkana. But when Hiragana character is used search does not work and no search results are returned.
Ex:
Searching names in Hiragana can not hit names in Katakana, and vice versa:​
To hit "姥谷 キツ"(the name is in Katakana), searching "きつ" (in Hiragana) though. it fails to get it.​
To hit "元廣 あえか" (phonetic chars in Katakana), searching "アエカ" though, it fails to get it.​
Does Azure search support any analyzer which supports all writing schemes (Hiragana, Kankana, Kanji etc) or I need to use some other technique for this?

Neither the Lucene nor the Microsoft Japanese analyzers generate katakana tokens for hiragana or vice-versa. The analyzer will create tokens for the given syllabary.
You can use the analyze API to see what tokens get generated for a particular string.
For instance, calling the analyze API with this input:
{
"text": "元廣 あえか",
"analyzer": "ja.microsoft"
}
returns:
{
"#odata.context": "https://service-name.search.windows.net/$metadata#Microsoft.Azure.Search.V2019_05_06.AnalyzeResult",
"tokens": [
{
"token": "元廣",
"startOffset": 0,
"endOffset": 2,
"position": 0
},
{
"token": "あえか",
"startOffset": 3,
"endOffset": 6,
"position": 1
}
]
}

Related

How to customize tokenization of numbers by the en.microsoft analyzer?

We are now using Azure search Microsoft language analyzers on some of language specific fields. In most of cases, it has better relevance than standard Lucene language analyzers. But we found an issue when verifying en.microsoft analyzer.
The problem is, if the field value contains digits. The analyzer is smart to allow redundant “0” in front the digit.
For example:
POST /analyze?api-version=2017-11-11
{
"text": "1",
"analyzer": "en.microsoft"
}
The response is:
"tokens": [
{
"token": "1",
"startOffset": 0,
"endOffset": 2,
"position": 0
},
{
"token": "nn1",
"startOffset": 0,
"endOffset": 2,
"position": 0
}
]
The problem is, that if the field value is “01”, then all text like “01”, “001”, “0001”, … will match that field.
We have a field to save the product attribute name/value pairs, for example, “brand:Contoso|size:1”. Then even searching “0001” can return the document with this field value. This is not what we want.
So, my question is, is there any way to customize the en.microsoft analyzer so that, we can take advantage of the powerful stemmer of the analyzer but avoid the auto “0” padding in front of the digit?
Unfortunately, you can't change how the Microsoft tokenizers normalize numbers. To workaround this limitation you could choose a different analyzer for product attributes or add a character filter to your analyzer configuration that encodes the numeric characters so the tokenizer ignores them, for example, map each digit into a character from outside your expected character set using the MappingCharFilter.You can find examples here, use MicrosoftLanguageStemmingTokenizer as your tokenizer.

Azure Search highlighting doesn't work for wildcards with scoring profiles

Azure Search supports highlighting with full text search which facilitates clients to locate the matched term in a returned document. I have provided a simple index schema below to illustrate the issue.
{
"name": "simple-index",
"fields": [
{
"name": "key",
"type": "Edm.String"
},
{
"name": "simplefield",
"type": "Edm.String"
}
],
"scoringProfiles": [
{
"name": "boostedprofile",
"functionAggregation": null,
"text": {
"weights": {
"simplefield": 5,
}
},
"functions": []
}
],
"corsOptions": null,
"suggesters": [],
"analyzers": [],
"tokenizers": [],
"tokenFilters": [],
"charFilters": []
}
For a normal search query like below, it works as expected and gives back the expected result.
search=foobar&highlight=simplefield
On extending the above query to use a wildcard query, things are again as expected with the response containing highlights on the terms matching the prefix. So far so good.
search=foo*&highlight=simplefield&querytype=full
After this when I apply a scoring profile on top of the previous query, the results are unexpected and no highlights are returned.
search=foo*&highlight=simplefield&querytype=full&scoringprofile=boostedprofile
How do I make highlights work for the wildcard queries when using a scoring profiles?
At the time of answering, this is a known limitation in Azure Search where highlighting doesn't work for wildcard queries when used with scoring profiles. Internally Azure Search uses a concept of highlighter which is responsible for the highlighting flow as a separate process that happens after search.
In the case of wildcard query, it involves looking up all terms in the index that match the provided prefix term and then use them to compose the highlighted text. Scoring profiles affect the way terms are looked up in index for highlighting. Due to that the result doesn't include any highlights.
As this is a specific limitation in wildcard queries, one workaround is to pre-process the index to avoid issuing wildcard/prefix queries. Please take a look at custom analysis (https://learn.microsoft.com/en-us/rest/api/searchservice/custom-analyzers-in-azure-search) You can, for example, use edgeNgram tokenfilter and store prefixes of words in the index and issue a regular term query with the prefix (with out the '*' operator)
I hope this is useful. Please vote on the feedback item to help us prioritize our development efforts to support other modes of highlighting that will support the above use-case. https://feedback.azure.com/forums/263029-azure-search/suggestions/32661961-implement-other-highlighters

Include fields other than count in azure facet results?

While faceting azure search returns the count for each facet field by default.How do I also get other searchable fields for every facet?
Ex When I facet for area , I want something like this.(description is a searchable field)
{
"area": [
{
"count": 1,
"description": "Acrylics",
"value": "ACR"
},
{
"count": 1,
"description": "Power",
"value": "POW"
}
]
}
Can someone please help with the extra parameters I need to send in the query?
Unfortunately there is no good way to do this as there is no direct support for nested faceting in Azure search (you can upvote it here). To achieve the result you want you would need to store the data together as a composite value as described by this workaround.

Lucene/Solr: Store offset information for certain keywords

We are using Solr to store documents with keywords; each keyword is associated with a span within the document.
The keywords were produced by some fancy analytics and/or manual work prior to loading them into Solr. A keyword can be repeated multiple times in a document. On the other hand, different instances of the same string in a single document can be connected with different keywords.
For example, this document
Bill studied The Bill of Rights last summer.
could be accompanied by the following keywords (with offsets in parentheses):
William Brown (0:4)
legal term (13:31)
summer 2011 (32:43)
(Obviously in other documents, Bill could refer to Bill Clinton or Bill Gates. Similarly, last summer will refer to different years in different documents. We do have all this information for all the documents.)
I know the document can have a field, say KEYWORD, which will store William Brown. Then when I search for William Brown I will get the above document. That part is easy.
But I have no idea how to store the info that William Brown corresponds to the text span 0:4 so I can highlight the first Bill, but not the second.
I thought I could use TermVectors, but I am not sure if/how I can store custom offsets. I would think this is a fairly common scenario ...
EDIT: edited to make clear that Bill can refer to different people/things in different documents.
EDIT2: edited to make clear that a document can contain homonyms (identical strings with different meanings).
Two Q Monte
Solution Pros:
Annotations logically stored with source docs
No knowledge of highlighter implementation or custom Java highlighter development required
Since all customization happens outside of Solr, this solution should be forward-compatible to future Solr versions.
Solution Cons:
Requires two queries to be run
Requires code in your search client to merge results from one query into the other.
With Solr 4.8+ you can nest child documents (annotations) underneath each primary document (text)...
curl http://localhost:8983/solr/update/json?softCommit=true -H 'Content-type:application/json' -d '
[
{
"id": "123",
"text" : "Bill studied The Bill of Rights last summer.",
"content_type": "source",
"_childDocuments_": [
{
"id": "123-1",
"content_type": "source_annotation",
"annotation": "William Brown",
"start_offset": 0,
"end_offset": 4
},
{
"id": "123-2",
"content_type": "source_annotation",
"annotation": "legal term",
"start_offset": 13,
"end_offset": 31
},
{
"id": "123-3",
"content_type": "source_annotation",
"annotation": "summer 2011",
"start_offset": 32,
"end_offset": 43
}
]
}
]
... using block join to query the annotations.
1) Annotation Query: http://localhost:8983/solr/query?fl=id,start_offset,end_offset&q={!child of=content_type:source}annotation:"William Brown"
"response":{"numFound":1,"start":0,
"docs":[
{
"id": "123-1",
"content_type": "source_annotation",
"annotation": "William Brown",
"start_offset": 0,
"end_offset": 4
}
]
}
Store these results in your code so that you can fold in the annotation offsets after the next query returns.
2) Source Query + Highlighting: http://localhost:8983/solr/query?hl=true&hl.fl=text&fq=content_type:source&q=text:"William Brown" OR id:123
(id:123 discovered in Annotation Query gets ORed into second query)
"response":{"numFound":1,"start":0,
"docs":[
{
"id": "123",
"content_type": "source",
"text": "Bill studied The Bill of Rights last summer."
}
],
"highlighting":{}
}
Note: In this example there is no highlighting information returned because the search terms didn't match any content_type:source documents. However we have the explicit annotations and offsets from the first query!
Your client code then needs to take the content_type:source_annotation results from the first query and manually insert highlighting markers into the content_type:source results from the second query.
More block join info on Yonik's blog here.
By default Solr stores the start/end position of each token once is tokenized, for instance using the StandardTokenizer. This info is encoded on the underline index. The use case that you described here sounds a lot like the SynonymFilterFactory.
When you define a synonym using the SynonymFilterFactory stating for instance that: foo => baz foo is equivalent to bar, the bar term is added to the token stream generated when the text is tokenized, and it will have the same offset information than the original token. So for instance if your text is: "foo is awesome", the term foo will have the following offset information (start=0,end=3) a new token bar(start=0,end=3) will be added to your index (assuming that you're using the SynonymFilterFactory at index time):
text: foo is awesome
start: 0 4 7
end: 3 6 13
Once the SynonymFilterFactory is applied:
bar
text: foo is awesome
start: 0 4 7
end: 3 6 13
So if you fire a query using foo, the document will match, but if you use bar as your query the document will also match since a bar token is added by the SynonymFilterFactory
In your particular case, you're trying to accomplish multi-term synonyms, which is kind of a difficult problem, you may need something more than the default synonym filter of Solr. Check this post from the guys at OpenSourceConnections and this other post from Lucidworks (the company behind Solr/Lucene). This two posts should provide additional information and the caveats of each approach.
Do you need to fetch the stored offsets for some later processing?

Solr5 search not displaying results based on score

I am implementing Solr search, the search order is not displaying on the basis of score. Lets say if use the search keywords as .net ios it's returning the results based on score. I have a field title which holds the following data
KeySkills:Android, ios, Phonegap, ios
KeySkills:.net, .net, .net, MVC, HTML, CSS
Here when i search .net ios as search keyword net, .net, .net, MVC, HTML, CSS should come first in the results and the score should be higher because it contains .net 3 times, but i am getting reverse result.
Is there any setting needs to be done in solr config file or in schema.xml file to achieve this or how can i sort the results based on max no of occurrence of the the search string. please help me to solve this.
Following is the result i get
{
"responseHeader": {
"status": 0,
"QTime": 0,
"params": {
"indent": "true",
"q": ".net ios",
"_": "1434345788751",
"wt": "json"
}
},
"response": {
"numFound": 2,
"start": 0,
"docs": [
{
"KeySkills": "Android, ios, Phonegap, ios",
"_version_": 1504020323727573000,
"score": 0.47567564
},
{
"KeySkills": "net, net, net, MVC, HTML, CSS",
"_version_": 1504020323675144200,
"score": 0.4726259
}
]
}
}
As you can see in Lucene's doc, score is not only estimated with the number of matching term:
score(q,d) = coord(q,d) · queryNorm(q) · ∑( tf(t in d)·
idf(t)²·t.getBoost()·norm(t,d) )
Where
tf(t in d) correlates to the term's frequency, defined as the number
of times term t appears in the currently scored document d.
idf(t) stands for Inverse Document Frequency. This value correlates
to the inverse of docFreq (the number of documents in which the term t
appears). This means rarer terms give higher contribution to the total
score.
coord(q,d) is a score factor based on how many of the query terms
are found in the specified document.
t.getBoost() is a search time boost of term t in the query q as
specified in the query text.
norm(t,d) encapsulates a few
(indexing time) boost and length factors:
Field boost
lengthNorm
computed when the document is added to the index in accordance with
the number of tokens of this field in the document, so that shorter
fields contribute more to the score.
When a document is added to the index, all the above factors are
multiplied. If the document has multiple fields with the same name,
all their boosts are multiplied together:
norm(t,d) = lengthNorm · ∏ f.boost()
So, here I guess that "KeySkills": "Android, ios, Phonegap, ios" is before your other document because it contains less words than the other one.
To check that, you can use this awesome tool, which is explain.solr.pl.

Resources