Liferay Elastic Search Query: Search for DLFileEntries that have a Custom Document Type - elasticsearch

I work with Liferay 7.2 and I need to make an Elasticsearch query that finds als DLFileEntries that have the Document Type "XY". Currently I need to do this in Postman.
I am already able to find all DLFileEntry:
{
"query": {
"bool": {
"must": [
{
"match": {
"entryClassName": "com.liferay.document.library.kernel.model.DLFileEntry"
}
}
]
}
}
}
But I need to find only these DLFileEntry that have Document Type "XY".
How can I do this?

You can simply add another match to the field fileEntryTypeId, where its value must be equal to the created Document Type id. You can find this id on table dlfileentrytype on column fileentrytypeid. Considering the id equals 37105, the query would be like this
{
"query": {
"bool": {
"must": [
{
"match": {
"entryClassName": "com.liferay.document.library.kernel.model.DLFileEntry"
}
},
{
"match": {
"fileEntryTypeId": "37105"
}
}
]
}
}
}
edit: Responding to your comment about how to search the DLFileEntry by its DLFileEntryType name, there is no direct way to do this as the DLFileEntryType is not indexed on Elastic Search by default. It would also probably need sub queries to achieve this and Elastic Search doesn't support sub queries.
With that in mind, the easiest approach I can think of is to customize the way DLFileEntry is indexed on Elastic Search, adding the field fileEntryTypeName. For that, you only need to implement a ModelDocumentContributor for DLFileEntry and add the fileEntryTypeName field to the document.
Basically, you just need to create a class like this:
package com.test.liferay.override;
import com.liferay.document.library.kernel.model.DLFileEntry;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.search.Document;
import com.liferay.portal.search.spi.model.index.contributor.ModelDocumentContributor;
import org.osgi.service.component.annotations.Component;
#Component(
immediate = true,
property = "indexer.class.name=com.liferay.document.library.kernel.model.DLFileEntry",
service = ModelDocumentContributor.class
)
public class DLFileEntryModelDocumentContributor
implements ModelDocumentContributor<DLFileEntry> {
#Override
public void contribute(Document document, DLFileEntry dlFileEntry) {
try {
document.addText(
"fileEntryTypeName", dlFileEntry.getDLFileEntryType().getName());
} catch (PortalException e) {
// handle error
}
}
}
As the DLFileEntryType name is localized, you should probably index it as a localized value:
package com.test.liferay.override;
import com.liferay.document.library.kernel.model.DLFileEntry;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.search.Document;
import com.liferay.portal.kernel.search.Field;
import com.liferay.portal.kernel.util.LocaleUtil;
import com.liferay.portal.search.spi.model.index.contributor.ModelDocumentContributor;
import org.osgi.service.component.annotations.Component;
import java.util.Locale;
#Component(
immediate = true,
property = "indexer.class.name=com.liferay.document.library.kernel.model.DLFileEntry",
service = ModelDocumentContributor.class
)
public class DLFileEntryModelDocumentContributor
implements ModelDocumentContributor<DLFileEntry> {
#Override
public void contribute(Document document, DLFileEntry dlFileEntry) {
try {
Locale siteDefaultLocale = LocaleUtil.getSiteDefault();
String localizedName = dlFileEntry
.getDLFileEntryType().getName(siteDefaultLocale);
String localizedField = Field.getLocalizedName(
siteDefaultLocale, "fileEntryTypeName");
document.addText(localizedField, localizedName);
} catch (PortalException e) {
// handle error
}
}
}
Now your query will be something like this:
{
"query": {
"bool": {
"must": [
{
"match": {
"entryClassName": "com.liferay.document.library.kernel.model.DLFileEntry"
}
},
{
"match": {
"fileEntryTypeName_en_US": "XY"
}
}
]
}
}
}
The name fileEntryTypeName_en_US depends on your site default locale. For example, if it is pt_BR, the name would be fileEntryTypeName_pt_BR.
Obs.: The fileEntryType name field is not unique, as it is localized, so you might find files with the same fileEntryType name but different fileEntryType.

Related

Creating a whitespace character filter

I want to use a custom analyzer with a pattern tokenizer and a custom token filter. But, before that step, I want to make the tokens on each whitespace. I know, I can use the whitespace analyzer but I also want to use my custom analyzer.
Basically, I want to generate a token on each special character and whitespace in a string.
For example, I have a string "Google's url is https://www.google.com/."
My tokens should be like "Google", "Google'", "Google's", "url", "is", "https", "https:", "https:/", "://", "//www","/www."... and so on.
Basically, I want to be my tokens like that of n-gram but only a limited one like the below which will break only on special character.
My tokenizerFactory files looks like this:
import org.apache.lucene.analysis.Tokenizer;
import org.apache.lucene.analysis.pattern.PatternTokenizer;
import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.index.IndexSettings;
import org.elasticsearch.index.analysis.AbstractTokenizerFactory;
import java.util.regex.Pattern;
public class UrlTokenizerFactory extends AbstractTokenizerFactory {
private final Pattern pattern;
private final int group;
public UrlTokenizerFactory(IndexSettings indexSettings, Environment environment, String name, Settings settings) {
super(indexSettings, name, settings);
String sPattern = settings.get("pattern", "[^\\p{L}\\p{N}]");
if (sPattern == null) {
throw new IllegalArgumentException("pattern is missing for [" + name + "] tokenizer of type 'pattern'");
}
this.pattern = Regex.compile(sPattern, settings.get("flags"));
this.group = settings.getAsInt("group", -1);
}
#Override
public Tokenizer create() {
return new PatternTokenizer(pattern, group);
}
}
My TokenFilterfactory file is currently empty.
You can simply use the whitespace tokenizer in your custom analyzer definition, below is the example of custom_analyzer which uses it.
{
"settings": {
"analysis": {
"analyzer": {
"my_custom_analyzer": { --> name of custom analyzer
"type": "custom",
"tokenizer": "whitespace", --> note this
"filter": [
"lowercase"
]
}
}
}
},
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "my_custom_analyzer" --> note this
}
}
}
}

Kibana search pattern issue

I am trying to create a elastic search query for one of my Library projects. I am trying to use regex but I do not get any result. I am trying to enter the following regex query.
GET /manifestation_v1/_search
{
"query": {
"regexp": {
"bibliographicInformation.title": {
"value": "python access*"
}
}
}
}
access is a wildcard so i want to create a query which takes as python access* not python access
Can anyone help me out who already has some experience in kibana?
you can try wildcard query
{
"query": {
"wildcard": {
"bibliographicInformation.title": {
"value": "saba safavi*"
}
}
}
}
You need to run regex query on keyword field and use .* instead of *
ex.
GET /manifestation_v1/_search
{
"query": {
"regexp": {
"bibliographicInformation.title": {
"value": "python access.*"
}
}
}
}
Regex is slower , you can also try prefix query
{
"query": {
"prefix": {
"bibliographicInformation.title": {
"value": "python access"
}
}
}
}
If field is of nested type then you need to use nested query
Update
For "text" type , field is stored as tokens. i.e
"python access" is stored as ["python","access"]. You query is trying to match "phython access*" with each of these tokens individually. You need to query against keyword field , which is stored as single value "phython access".

ElasticSearch 6.x and NEST simple query

Actually I'm a newcomer to ElasticSearch and got stuck with just a simple NEST query.
Here is my class to store data in ElasticSearch:
public class MyClass
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Language { get; set; }
}
I need to get documents by the Language (e.g. Language == "eng")
I use the NEST 6.x
Here is the SerchDescriptor
searchDescriptor = new SearchDescriptor<MyClass>()
.Index(indexName)
.Query(q => q.Term("Language", "eng"));
it produces the request:
{
"query": {
"term": {
"Language": {
"value": "eng"
}
}
}
}
but the right request is
{
"query": {
"term": {
"Language": "eng"
}
}
}
How can I get the right request via NEST?
Both forms are valid; the former is the long form of term query that accepts other properties such as boost and _name.
NEST typically serializes request types to the long form, and deserializes from the long form.

Index field is mapped as text instead of keyword

Experiencing an issue with ES,
I have a mapping for a user type, specifying a field as keyword
GET _template/user_template
Returns:
{
...
"primary_user": {
"type": "keyword"
}
}
The following filter request will return with hits
GET users/user/_search
{
"query": {
"bool": {
"filter": {
"term": {
"primary_user.keyword": "AWBFyulcxxxxxxxx"
}
}
}
}
}
The following request will return with 0 hits.
GET users/user/_search
{
"query": {
"bool": {
"filter": {
"term": {
"primary_user": "AWBFyulcxxxxxxxx"
}
}
}
}
}
From the Dev tools autocomplete, I can see the ES regards the primary_user as text.
What am I missing?
Check the name of the index with the template index pattern: the template will be applied only to index with name matching the index pattern.
In addition templates are only applied at index creation time and changing a template will have no impact on existing indices: if you have updated the template, you have to create a new index (ord deleting and recreating an existing one) for viewing the changes in the mapping.

Combination of and or elasticsearch

How to write query for following condition in elasticsearch
Select * from table1 where (cnd1 or cond2) and (cnd3)
My cond2 value is from nested object . My json object is below
details={ "name"="name1",
"address":"{
"city":"city1"
}"
}
I need to take city from above object
details.address.city
Is above syntax is right , if not how to get value of second object city.
{
"bool" : {
"must" : cond3,
"should" : [
cond1,
cond2
],
"minimum_should_match" : 1
}
}
go through this link for more info https://www.elastic.co/guide/en/elasticsearch/reference/2.3/query-dsl-bool-query.html
You can easily create a conditional queries with Elasticsearch. But there is some weird situation of your data section.
details={ "name"="name1",
"address":"{
"city":"city1"
}"
}
Elasticsearh save your data as a json object, but you should give your data as a json. In this section, there is an object, you try to sent. Let us examine:
There is a name attribute of detail object, it is a string. And also there is a address attribute, and it is a string too. It should be an object which has to include a city attribute if you want to reach this object via details.address.city. Now we try to fix:
{
"id":...,
...
"details": {
"name": "name1",
"address": {
"city": "city1"
}
}
}
In this case, I remove double quotation marks of details object. Now, you can reach city attribute of json as a json object. Now, we create a query to reach cities:
{
"query": {
"bool": {
"must": {
"term": {
"your-json-attribute": "???"
}
},
"should": [
{
"term": {
"your-json-attribute": "???"
}
},
{
"term": {
"your-json-attribute": "???"
}
}
]
}
}
}
I use term query but there is lots of another query types. You can check them on documentation. But for And and Or, you can use bool query. Check https://www.elastic.co/guide/en/elasticsearch/reference/2.0/query-dsl-bool-query.html

Resources