Wildcard search not working for path-index - wildcard

Here is the query which gives the desired results:
import module namespace search = "http://marklogic.com/appservices/search" at "/MarkLogic/appservices/search/search.xqy";
search:search("( ( collectionId: ( "54930050DETB6CP71D38" ) ) ) sort:documentCreationDateDES",
<options xmlns="http://marklogic.com/appservices/search">
<term>
<empty apply="all-results"/>
<term-option>unstemmed</term-option>
<term-option>case-insensitive</term-option>
<term-option>punctuation-insensitive</term-option>
<term-option>wildcarded</term-option>
</term>
<additional-query>{cts:directory-query('/dir/subdir01/', "1")}</additional-query>
<transform-results apply="transformed-result" ns="http://searchgui/search" at="/customResultSet.xqy"/>
(:
Constraints or Search Criteria.
- collectionId
- creationDate
:)
<search:constraint name="collectionId">
<search:range type="xs:string" facet="false" collation="http://marklogic.com/collation/en">
<search:path-index ns="http://any.anyns.com/2013/doc">
//cd:documentCollections/cd:collection/cd:id
</search:path-index>
</search:range>
</search:constraint>
<search:constraint name="creationDateRange">
<search:range type="xs:dateTime" facet="false">
<search:bucket ge="0" lt="0" name="documentCreationDate">
Search by Document Creation date / uploaded date
</search:bucket>
<search:element ns="http://any.anyns.com/2013/doc" name="documentCreationDate"/>
<facet-option>limit=10</facet-option>
<facet-option>item-order</facet-option>
<facet-option>descending</facet-option>
</search:range>
</search:constraint>
(:
Sorting options:
- collectionId
- creationDate
:)
<search:operator name="sort">
(: Document Collection Id :)
<search:state name="collectionIdASC">
<search:sort-order direction="ascending" type="xs:string">
<search:path-index ns="http://any.anyns.com/2013/doc">
//cd:documentCollections/cd:collection/cd:id
</search:path-index>
</search:sort-order>
</search:state>
<search:state name="collectionIdDES">
<search:sort-order direction="descending" type="xs:string">
<search:path-index ns="http://any.anyns.com/2013/doc">
//cd:documentCollections/cd:collection/cd:id
</search:path-index>
</search:sort-order>
</search:state>
(: Creation Date :)
<search:state name="documentCreationDateASC">
<search:sort-order direction="ascending" type="xs:dateTime">
<search:element ns="http://any.anyns.com/2013/doc" name="documentCreationDate"/>
</search:sort-order>
</search:state>
<search:state name="documentCreationDateDES">
<search:sort-order direction="descending" type="xs:dateTime">
<search:element ns="http://any.anyns.com/2013/doc" name="documentCreationDate"/>
</search:sort-order>
</search:state>
</search:operator>
</options>, 1, 100);
But when i replace the search-criteria with wild-cards as below, it does not return any results:
"( ( collectionId: ( "* *54930050DETB6CP71D38* *" ) ) ) sort:documentCreationDateDES"
Though i set the <term-option> as wildcarded still it does not work, any suggestions or pointer as to what i might be missing would help.
I have tried changing other term-option from sensitive to insensitive and back in different combinations but it does not work, nor does stemmed or unstemmed works.

Term-options don't apply to range constraints, only facet-options do. And a facet-option wildcarded does not exist. Range constraints are ideal for selecting ranges, e.g. num GT x AND num LT y, but not suited for mid-string matches.
I think you'll have to create a word or value constraint for the same path to be able to use wildcards on it. Unfortunately, you can't just create a word or value constraint on a path as specific as you have in your collectionId constraint. You'd have to create a field with that path.
HTH!

The following description answers the how, its a supplement to this answer by #grtjn.
This is the part which was changed in the query:
<search:constraint name="collectionId">
<search:word>
<search:field name="collectionIdField"/>
<search:term-option>case-insensitive</search:term-option>
<search:term-option>unstemmed</search:term-option>
<search:term-option>wildcarded</search:term-option>
<search:term-option>punctuation-insensitive</search:term-option>
</search:word>
</search:constraint>
I could use the above in my query because i created a field - collectionIdField of type - path, with path as //cd:documentCollections/cd:collection/cd:id.
This is the query used for creating the field, this can also be done from the admin-console but i prefer the query way:
xquery version "1.0-ml";
import module namespace admin = "http://marklogic.com/xdmp/admin" at "/MarkLogic/admin.xqy";
(:
get admin configuration
:)
let $config := admin:get-configuration()
(:
Specify the database where you want to create this field
:)
let $dbid := xdmp:database("My-Database")
(:
The field you want to create
:)
let $field-name := "collectionIdField"
(:
Since you are creating a path-field, specify the path.
Multiple field-paths can be specified
:)
let $field-paths := (
admin:database-field-path("//cd:documentCollections/cd:collection/cd:id", xs:double(1.0))
)
(:
Link database-field with field-path
:)
let $fieldspec := admin:database-path-field($field-name, $field-paths)
let $addFieldConfig := admin:database-add-field($config, $dbid, $fieldspec)
(:
Save the new database-add-field configuration to create the field
:)
return admin:save-configuration($addFieldConfig)
So here is my final query which actually worked:
import module namespace search = "http://marklogic.com/appservices/search" at "/MarkLogic/appservices/search/search.xqy";
search:search("( ( collectionId: ( "54930050DETB6CP71D38" ) ) ) sort:documentCreationDateDES",
<options xmlns="http://marklogic.com/appservices/search">
<term>
<empty apply="all-results"/>
<term-option>unstemmed</term-option>
<term-option>case-insensitive</term-option>
<term-option>punctuation-insensitive</term-option>
<term-option>wildcarded</term-option>
</term>
<additional-query>{cts:directory-query('/dir/subdir01/', "1")}</additional-query>
<transform-results apply="transformed-result" ns="http://searchgui/search" at="/customResultSet.xqy"/>
(:
Constraints or Search Criteria.
- collectionId
- creationDate
:)
<search:constraint name="collectionId">
<search:word>
<search:field name="collectionIdField"/>
<search:term-option>case-insensitive</search:term-option>
<search:term-option>unstemmed</search:term-option>
<search:term-option>wildcarded</search:term-option>
<search:term-option>punctuation-insensitive</search:term-option>
</search:word>
</search:constraint>
<search:constraint name="creationDateRange">
<search:range type="xs:dateTime" facet="false">
<search:bucket ge="0" lt="0" name="documentCreationDate">
Search by Document Creation date / uploaded date
</search:bucket>
<search:element ns="http://any.anyns.com/2013/doc" name="documentCreationDate"/>
<facet-option>limit=10</facet-option>
<facet-option>item-order</facet-option>
<facet-option>descending</facet-option>
</search:range>
</search:constraint>
(:
Sorting options:
- collectionId
- creationDate
:)
<search:operator name="sort">
(: Document Collection Id :)
<search:state name="collectionIdASC">
<search:sort-order direction="ascending" type="xs:string">
<search:path-index ns="http://any.anyns.com/2013/doc">
//cd:documentCollections/cd:collection/cd:id
</search:path-index>
</search:sort-order>
</search:state>
<search:state name="collectionIdDES">
<search:sort-order direction="descending" type="xs:string">
<search:path-index ns="http://any.anyns.com/2013/doc">
//cd:documentCollections/cd:collection/cd:id
</search:path-index>
</search:sort-order>
</search:state>
(: Creation Date :)
<search:state name="documentCreationDateASC">
<search:sort-order direction="ascending" type="xs:dateTime">
<search:element ns="http://any.anyns.com/2013/doc" name="documentCreationDate"/>
</search:sort-order>
</search:state>
<search:state name="documentCreationDateDES">
<search:sort-order direction="descending" type="xs:dateTime">
<search:element ns="http://any.anyns.com/2013/doc" name="documentCreationDate"/>
</search:sort-order>
</search:state>
</search:operator>
</options>, 1, 100);
Field helps with the wildcard and it has its own term-options to be supplied in the <word> element as shown above.

Related

Why does total result count change as I switch the page in Marklogic?

When I execute the below code with different values set for variable $Start as declared in the code, the value fetched each time for total count keeps changing-
import module namespace search = "http://marklogic.com/appservices/search" at "/MarkLogic/appservices/search/search.xqy";
let $SearchWord := 'AB:"nuclear power plant" OR AB:"nuclear power station"'
let $SearchOption :=
<options xmlns="http://marklogic.com/appservices/search">
<constraint name="AB">
<word>
<element ns="" name="ti"/>
<term-option>case-insensitive</term-option>
<term-option>diacritic-insensitive</term-option>
<term-option>punctuation-insensitive</term-option>
<term-option>whitespace-insensitive</term-option>
</word>
</constraint>
</options>
let $Start := 1
let $pageLength := 10
let $SearchResponse := search:search($SearchWord, $SearchOption, $Start, $pageLength)
return $SearchResponse

Can I use indexes for speeding up select queries over dateTime ranges in BaseX?

I would like to ask about the way to speed up the select queries in a Basex database.
I have for example the following xml in a database with many events(650000 approximately)
<EventList>
<Event>
<ID>317849</ID>
<Type>Measurement</Type>
<TimeStamp>2016-03-15T18:00:09.409</TimeStamp>
<Space>BIOCAT</Space>
<SourceID>BIOCAT.TE310A</SourceID>
<Content>
<Measurement>
<value>920</value>
</Measurement>
</Content>
</Event>
<Event>
<ID>317850</ID>
<Type>Measurement</Type>
<TimeStamp>2016-03-15T18:05:09.409</TimeStamp>
<Space>BIOCAT</Space>
<SourceID>BIOCAT.TE310A</SourceID>
<Content>
<Measurement>
<value>920</value>
</Measurement>
</Content>
</Event>
</EventList>
I am retrieving the events with the following code that selects with respect to the datetime of the Timestamp node
for $b in doc('mydb/my.xml')//EventList/Event
let $date_string as xs:string := xs:string($b/TimeStamp/data())
let $date as xs:dateTime := xs:dateTime($date_string)
where $date ge xs:dateTime('"+startdate+"')
and $date le xs:dateTime('"+enddate+"')
and $b/Type='"+EventType+"'
return $b
But it it is very slow it makes one minute to return 60 events.
There are many data in the BaseX database.
How can I speed up the request or my database?
BaseX currently does not have a range index for xs:dateTime, but you can use the text index for getting all events with a given event Type by moving the comparison into the XPath:
for $b in //EventList/Event[Type = 'Measurement']
let $date as xs:dateTime := xs:dateTime($b/TimeStamp)
where $date ge xs:dateTime('2016-03-15T18:00:00.000')
and $date le xs:dateTime('2016-03-15T19:00:00.000')
return $b
In the Info View of the GUI you can see that the text index is applied:
Compiling:
rewriting descendant-or-self step(s)
applying text index for "Measurement"
pre-evaluating "2016-03-15T18:00:00.000" cast as xs:dateTime
pre-evaluating "2016-03-15T19:00:00.000" cast as xs:dateTime
Optimized Query:
for $b_0 in db:text("mydb/my.xml", "Measurement")
/parent::*:Type/parent::*:Event[parent::*:EventList]
let $date_1 as xs:dateTime := $b_0/TimeStamp cast as xs:dateTime?
where (($date_1 ge "2016-03-15T18:00:00")
and ($date_1 le "2016-03-15T19:00:00"))
return $b_0

How to write own Solr custom functional query to apply few selected field

Base on my requirement i have to write and apply function on few query selection fields.
The below query is, i have to convert from mysql to solr. Is possible to apply custom function on Solr or any other way to achieve this in solr kindly share.
Mysql:
select t.titleNo ,
(select udConvertCurreny(t.currentPrice,T.currency, #preferredCurrency)
from offerTitle
where titleNo = T.titleNo
and applyDate = now() ) as price
from title as T;
Function:
DELIMITER $$
CREATE FUNCTION udfConvertCurrency ( currentPrice decimal, currency varchar, preferredCurrency varchar)
RETURNS INT
BEGIN
IF currency != 'rs' THEN
currentPrice = currentPrice / (select currencyRate from currency where currencytype =currency );
RETURN currentPrice;
END; //
DELIMITER ;

How to use a FireDAC TFDConnection to iterate through tables, fields and field definitions

I am teaching myself to use SQLite and FireDAC together in Delphi. I am not very experienced with the latest incarnations of databases and tools so after writing a very simple application to display a single table from an SQLite file, I decided that I would put together a simple viewer 'frame' that would help me learn and maybe give me (eventually) a debugging tool to put in my Application for engineering use.
So, I've used a simple TTreeView and I wish to populate it with a hierarchy of 'databases' (catalogues?), 'tables', 'field names' and 'field types'. So far it has been remarkably easy to list the catalogues, tables and fields (using TFDConnection.Getxxxxx) but I cant see how to go deeper to get field definitions. Is this possible to do from a TFDConnection? Or do I need to open a temporary query?
My existing code is shown below and my 'field types' would be a further nested loop when shown as '// xxxxxxxxxxxxxxxxxxx'
procedure TForm1.Button1Click(Sender: TObject);
procedure DatabaseToTreeView( AConnection : TFDConnection; ATreeView : TTreeView );
procedure ProcessConnection;
procedure ProcessCatalogueName( const ACatalogueName : string; ARoot : TTreeNode );
procedure ProcessTableName( const ATableName : string; ARoot : TTreeNode );
var
List : TStrings;
{Node : TTreeNode;}
I : integer;
begin
List := TStringList.Create;
try
AConnection.GetFieldNames( ACatalogueName, '', ATableName, '', List );
for I := 0 to List.Count-1 do
begin
{Node := }ATreeView.Items.AddChild( ARoot, List[I] );
// xxxxxxxxxxxxxxxxxxx
end;
finally
List.Free;
end;
end;
var
List : TStrings;
Node : TTreeNode;
I : integer;
begin
List := TStringList.Create;
try
AConnection.GetTableNames( ACatalogueName, '', '', List );
for I := 0 to List.Count-1 do
begin
Node := ATreeView.Items.AddChild( ARoot, List[I] );
ProcessTableName( List[I], Node );
end;
finally
List.Free;
end;
end;
var
List : TStrings;
Node : TTreeNode;
I : integer;
begin
List := TStringList.Create;
try
AConnection.GetCatalogNames( '', List );
if List.Count = 0 then
ProcessCatalogueName( '', nil )
else
for I := 0 to List.Count-1 do
begin
Node := ATreeView.Items.AddChild( nil, List[I] );
ProcessCatalogueName( List[I], Node );
end;
finally
List.Free;
end;
end;
begin
ATreeView.Items.Clear;
ATreeView.Items.BeginUpdate;
try
ProcessConnection;
finally
ATreeView.Items.EndUpdate;
end;
end;
begin
FDConnection1.Open;
FDQuery1.Active := true;
DatabaseToTreeView( FDConnection1, TreeView1 );
end;
Many thanks, Brian.
One solution is to instantiate a TFDTable, connect it to AConnection and call FieldDefs.Update. This won't fetch any data.
Use the TFDMetaInfoQuery component. It is unified for getting metadata information, so it's usable with any kind of supported DBMS. It populates metadata resultsets by the requested MetaInfoKind and given DBMS object description.
Instead of using a temporary query with a false condition to get table schema without any data (such as "select * from tablename where 1=0" - I assume that is what you meant), depending on your database, you could also use a query to get table information. Like;
For MySQL:
show columns from tablename;
For SQLite:
PRAGMA table_info(tablename)
For MS SQL Server:
select column_name, data_type, character_maximum_length from INFORMATION_SCHEMA.COLUMNS where table_name = 'tablename';
I believe PostgreSQL also has such a function, however I dont have a pgsql installation handy at this time.

Applying suggestion-source constraints for typeahead in Marklogic

Say, I have 5 documents that belong to either of different collections such as:
Biography, Fiction, Humour, Adventure
For instance, document 1 is in Adventure Collection:
<Book>
<title>Harry Potter and the Deathly Hallows</title>
<Author>J.K.Rowling</Author>
<year>2007</year>
</Book>
document 2, is in Biography Collection:
<Book>
<title>Steve Jobs</title>
<Author>Walter Issacson</Author>
<year>2011</year>
</Book>
Now I want to apply suggest on year element. I want to apply this on collections i.e. for example-suggest on Biography collections
I have defined element range index on year and ingested sample documents using application loader and configured collections for documents in document settings.
Follwing is my XQUERY code:
xquery version "1.0-ml";
import module namespace search = "http://marklogic.com/appservices/search"
at "/MarkLogic/appservices/search/search.xqy";
let $options :=
<options xmlns="http://marklogic.com/appservices/search">
<constraint name="Group">
<collection prefix="Biography/"/>
</constraint>
<suggestion-source ref="Group">
<range collation="http://marklogic.com/collation/"
type="xs:string" >
<element name="year"/>
</range>
</suggestion-source>
</options>
return
search:suggest("Group:20", $options)
On running this query I am getting suggestions for both 2011 and 2007 which is not what I am expecting.
Expected suggestion is 2011 (as only Biography collection should be searched).
I have refered this doc on search:suggest but I am not able to find out what exactly is the mistake.
Where am I doing wrong?
Shrey:
The values from the suggestion source are substituted for the values from the referenced constraint. In other words, the options say that input qualified by the group constraint should come from the year range index, which is what you're seeing. For more detail, please see:
http://docs.marklogic.com/guide/search-dev/search-api#id_40748
To filter a set of suggestions, you can call search:suggest() with two string queries. The first provides the input for the suggestions. The second provides the filtering constraint. In the case above, the filtering constraint would be the Biography collection. For more detail, please see:
http://docs.marklogic.com/guide/search-dev/search-api#id_91911
Hoping that helps
However, I am able to achieve the required output using additional-query in options as follows:
xquery version "1.0-ml";
import module namespace search = "http://marklogic.com/appservices/search"
at "/MarkLogic/appservices/search/search.xqy";
let $options :=
<options xmlns="http://marklogic.com/appservices/search">
<additional-query>{cts:collection-query("Biography")}
</additional-query>
<constraint name="Search_Element">
<range collation="http://marklogic.com/collation/"
type="xs:string" >
<element name="year"/>
</range>
</constraint>
<suggestion-source ref="Search_Element">
<range collation="http://marklogic.com/collation/"
type="xs:string" >
<element name="year"/>
</range>
</suggestion-source>
</options>
return
search:suggest("Search_Element:20", $options)
Still, I was wondering how could it be done without using additional-query paramater because it would be more optimized to use collection constraint for above.

Resources